• 初识Thread类与创建多线程的方法


    目录

    1.创建一个线程

    2.start()方法与run()方法

    3.查看线程

    4.创建线程的各种方法

    4.1实现Runnable接口

    4.2使用匿名内部类

    4.3使用匿名内部类,实现Runnable

    4.4使用Lambda表达式


    1.创建一个线程

    Java操作线程最核心的类就是Thread类

    创建线程有很多方法,下面我们写一个Mythread类继承 Thread 类重写run()方法来创建线程

    1. package thread;
    2. class MyThread extends Thread{
    3. public void run(){
    4. System.out.println("hello world!");
    5. }
    6. }
    7. public class ThreaDemo1 {
    8. public static void main(String[] args) {
    9. Thread t = new MyThread();
    10. }
    11. }

    这里的Thread类不需要import包,是因为这个类和String,StringBuffer这些类一样是在java.lang包中,已经自动导入了!

    run()方法是重写了Thread类的run()方法,重写就是和父类方法名参数都相同,子类的方法通过动态绑定机制被调用

    就像上面的:

    1. Thread t = new MyThread();
    2. t.run();

    这里的t是父类的引用,调用的 run()仍然是子类的方法,本质上t还是指向子类对象

    重载是同一个作用域,多个方法的方法名相同,参数个数或类型不同的方法

    2.start()方法与run()方法

    我们用t调用一个strat方法

    1. public class ThreaDemo1 {
    2. public static void main(String[] args) {
    3. Thread t = new MyThread();
    4. t.start();
    5. }
    6. }

    这里的hello world和我们直接在打印出来的hello world是不同的!!!

    这里的是由 t.start()创建了一个新的线程,然后由线程负责执行t.run(),打印出hello world!

      t.start()创建新的线程时,调用了操作系统的API,通过操作系统内核创建新线程的PCB,并把要执行的指令交给这个PCB,当PCB被调度到CPU上执行的时候,就能执行到run()方法中的代码了

    直接打印hello world时,java进程就只有一个线程(就是调用main方法的线程)也就是主线程

    通过 t.start(),主线程调用了t.start(),t.start()创建出新的线程,新的线程调用t.run();

    当run()方法执行完毕,新的的线程就自动销毁

    创建线程归结到底还是要解决并发编程问题,我们来看一个并发的例子

    1. class MyThread extends Thread{
    2. public void run(){
    3. while(true){
    4. System.out.println("hello world!");
    5. //休眠
    6. try {
    7. Thread.sleep(1000);
    8. } catch (InterruptedException e) {
    9. throw new RuntimeException(e);
    10. }
    11. }
    12. }
    13. }
    14. public class ThreaDemo1 {
    15. public static void main(String[] args) {
    16. Thread t = new MyThread();
    17. t.start();
    18. while(true){
    19. System.out.println("hello main!");
    20. try {
    21. Thread.sleep(1000);
    22. } catch (InterruptedException e) {
    23. throw new RuntimeException(e);
    24. }
    25. }
    26. }
    27. }

    这段代码并不是只执行到一个循环,死循环出不来了,而是交替执行的

     这就是并发执行的效果,执行的顺序也是不确定的,主要原因是:操作系统调度线程的时候是"抢占式执行",具体哪个线程先执行,哪个线程后执行,都是不确定的,取决于操作系统调度策略

    虽然也是有优先级的,但是从应用程序方面来看到的效果是随机的,我们在程序上无法修改的

    如果我们只执行t.run()会是什么情况呢?

     结果

    这里只执行了run方法,没有执行hellomain这里,是因为只有一个主线程是单线程工作的

    不会交替执行,这就是单线程和多线程的差异

    run()和start()的区别

    run是线程里的方法,描述的是线程要执行的任务,但是线程还没有执行,只有调用start后,线程才会开始运行,调用后会申请线程并执行run方法,执行完后进入销毁线程阶段,也就是说strat才是真正创建了线程,并且线程是独立的执行流

    3.查看线程

    我们可以使用jdk自带的工具jconsole查看当前的java进程中的所有线程

    这个工具一般路径:C:\Program Files\Java\jdk1.8.0_192\bin

    双击打开运行会看到本地进程

    接下来点击一下我们运行的程序的线程

     

    点击线程

     可以看到有很多线程

    详细信息 

     其它的线程都是JVM自带的线程

    注意:如果打开工具本地进程什么也没有,可以尝试用右键,管理员方式运行

     new Thread 对象时,不创建线程,调用start才是创建PCB才有真实的线程

    主线程调用就是start方法写到main方法中被调用

    4.创建线程的各种方法

    Java中创建线程的方法有很多种,上面使用的就是继承Thread类,重写run()方法的方法,下面了解一下其他三种方法

    4.1实现Runnable接口

    回顾:

    抽象类和普通类的区别:抽象类不能实例化,不能直接new,必须有子类继承抽象类,然后抽象类中有抽象方法,抽象方法没有方法体,需要子类重写抽象方法

    接口比抽象类更进一步,抽象类除抽象方法之外还有普通方法和属性,接口则是只有抽象方法

    1. class MyRunnable implements Runnable{
    2. public void run(){
    3. System.out.println("hello thread!");
    4. }
    5. }
    6. public class ThreadDemo2 {
    7. public static void main(String[] args) {
    8. Runnable runnable = new MyRunnable();
    9. Thread t = new Thread(runnable);
    10. t.start();
    11. }
    12. }

    Runnable是描述任务,具体执行细节就是run()方法,任务还要交给线程来执行

    使用Runnable接口达到了解耦合的目的,将线程和线程的任务分开,如果要修改代码,代码改动就比较小

    4.2使用匿名内部类

    1. public class ThreadDemo3 {
    2. public static void main(String[] args) {
    3. Thread t = new Thread(){
    4. @Override
    5. public void run() {
    6. System.out.println("hello world!");
    7. }
    8. };
    9. t.start();
    10. }
    11. }

    这里创建了一个Thread的子类,子类是匿名的,还创建了子类的实例,并且让t指向实例 

    4.3使用匿名内部类,实现Runnable

    1. public class ThreadDemo4 {
    2. public static void main(String[] args) {
    3. Thread t = new Thread(new Runnable() {
    4. @Override
    5. public void run() {
    6. System.out.println("hello world!!");
    7. }
    8. });
    9. t.start();
    10. }
    11. }

    写法和1本质相同,只不过把实现Runnable 任务交给匿名内部类的语法,此处是创建了一个类,实现Runnable,同时创建了实例 ,并且把实例传给Thread的构造方法(匿名内部类的创建的实例作为Thread的构造方法参数)

    4.4使用Lambda表达式

    这是比较简单的,推荐的写法

    1. public class ThreadDemo5 {
    2. public static void main(String[] args) {
    3. Thread t = new Thread(() -> {
    4. System.out.println("hello world!!");
    5. });
    6. t.start();
    7. }
    8. }

    把任务通过Lambda表达式来描述,直接把Lambda表达式传给Thread的构造方法

  • 相关阅读:
    PHP yield
    watch和computed的区别以及选择?
    (C++ STL) 详解vector模拟实现
    拆除联想一体机M7131z无线网卡
    tcp/ip协议和opc协议对比详解
    C语言——冒泡排序
    矩阵与线性变换
    大专三年总结2019-2022
    物联网智能家居基本方法实现之经典
    健身房系统瑜伽馆游泳馆篮球馆课程售卖课程预约多门店管理私教预约教练端会员卡办理商城
  • 原文地址:https://blog.csdn.net/chenchenchencl/article/details/128106312