【Java 并发编程】 01 多线程的实现

常用的实现多线程的2种方式:继承 Thread 或者实现 Runanable 接口

Thread 类 实现了 Runnable 接口

public class Thread implements Runnable {}

//继承 Thread 类

public class MyThread extends Thread {
    /*
       static Thread currentThread(),返回正在执行的线程对象的引用
       public static void sleep(long millis) 当前正在执行的线程以指定毫秒数暂定(暂时停止执行),毫秒结束后继续执行

     */
    @Override
    public void run() {
        for (int i = 0; i <5 ; i++) {
            System.out.println(this.getName()+ "卖票"+i);
            //  使用Thread类中的方法 String getName(),可以返回线程的名称。
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class MainThread {
    public static void main(String[] args){
        // 启动3个线程t1,t2,t3;每个线程各循环5次!

        MyThread t1=new MyThread();
        MyThread t2=new MyThread();
        MyThread t3=new MyThread();
        t1.start();
        t2.start();
        t3.start();
    }

}

结果:
Thread-1卖票0
Thread-0卖票0
Thread-2卖票0
Thread-0卖票1
Thread-0卖票2
Thread-0卖票3
Thread-0卖票4
Thread-1卖票1
Thread-1卖票2
Thread-2卖票1
Thread-1卖票3
Thread-2卖票2
Thread-1卖票4
Thread-2卖票3
Thread-2卖票4

实现 Runnable 接口

Runnable接口中有一个抽象方法run
public interface Runnable { public abstract void run(); }

public class DemoRunnable implements  Runnable {
    @Override
    public void run() {
        for (int i = 0; i <5 ; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}



public class MIanRunnable {
    public static void main(String[] args){
        //实例化DemoRunnable 对象
        DemoRunnable r=new DemoRunnable();
        //创建线程对象
        Thread t0=new Thread(r,"0号窗口");
        Thread t1=new Thread(r,"1号窗口");
        Thread t2=new Thread(r,"2号窗口");
        t0.start();
        t1.start();
        t2.start();

    }
}

结果:
1号窗口0
1号窗口1
2号窗口0
0号窗口0
0号窗口1
0号窗口2
0号窗口3
0号窗口4
2号窗口1
2号窗口2
2号窗口3
2号窗口4
1号窗口2
1号窗口3
1号窗口4

Thread 中的 start() 方法分析

是不是用一种疑问,逻辑业务在 run 方法中,为什么开启线程 要用start() 方法呢?

start() 源码如下所示:

public synchronized void start() {
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    group.add(this);

    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}
  • 检查线程的状态,是否可以启动;
  • 把线程加入到线程group中;
  • 调用了start0()方法。

Start方法中最终调用的是start0方法,并不是run方法,我们查看 start0() 方法,start0是一个native方法,也称为JNI(Java Native Interface)方法。JNI方法是java和其它语言交互的方式。同样也是java代码和虚拟机交互的方式,虚拟机就是由C++和汇编所编写。(一句话概括 ,native 修饰的方法 实在JVM 中的实现的,也就是说 start0() 方法 jvm 中,JVM 运行的 run() ) 👉 线程的生命周期
在这里插入图片描述

*the Java Virtual Machine calls the run method of this thread。
java虚拟机调用这个线程的run方法。*

private native void start0();

我们看一下run 方法,发现有一个target ,target 又是什么呢?

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

查看 Thread 的构造函数,返现target 是一个Runnable的实现对象,

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

查看Thread 中 初始化方法,

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals){
   // target 为成员变量
  this.target = target;
}

在这里插入图片描述

Thread 和 Ruannable 区别

Thread,是一个类,实现是 Ruannable 接口。Ruannable 是一个接口。所以继承thread类实现多线程,其实也相当于是实现runnable接口的run方法。

java 是单继承语言,一个类只能有一个父类,但是可以实现多个接口,Ruannable的扩展性更加好一些,避免了java中单继承的局限性。

多个线程基于某一个Runnable对象建立的,共享Runnable对象资源,增加程序的健壮性,实现了解耦操作,代码和线程独立。

继承 Thread 类, run 方法实现在 Thread 子类中,thread 对象运行自己的 run 方法逻辑,创建对象以及业务逻辑没有分离,实现Runnable 接口,run方法逻辑转移到 Runnable 的实现类中,是调用 Runnable 实现的 run 方法逻辑,可以将创建对象和执行逻辑业务分离开来,线程控制逻辑在Thread类中,业务运行逻辑在Runnable实现类中。解耦更为彻底
在这里插入图片描述

通过以上比较,推荐使用 Ruannable 接口 实现多线程 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章