首页 > 编程 > Java > 正文

Java中的多线程

2019-11-06 07:01:18
字体:
来源:转载
供稿:网友

前言

  昨晚在看死锁相关的东西,看到了synchronized关键字,然后就想写一篇关于synchronized关键字的博客,就去仔细看了看相关的东西。synchronized关键字在使用多线程的时候使用,于是复习一下多线程的东西,写篇博客加深一下印象。   java中实现多线程的方式有两种,一是继承Thread类,二是实现Runnable接口,先看继承Thread类。

继承Thread

  Threadjava.lang包中的一个类,实现了Runnable接口,Runnable接口源码如下,简单粗暴。

public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run();}

  ClassExtendsThread类,继承了Thread类,在run方法中依次递减打印出10到1。

public class ClassExtendsThread extends Thread { PRivate int num = 10; @Override public void run() { for (int i = 0 ; i < 10 ; i++) { if (num > 0) { // 打印出当前线程名字和num当前的值 System.out.println(currentThread().getName() + "--->" + num--); } } }}

  main函数代码如下:

public class DemoTest { public static void main(String[] args) { ClassExtendsThread thread1 = new ClassExtendsThread(); ClassExtendsThread thread2 = new ClassExtendsThread(); thread1.start(); thread2.start(); }}

  运行结果如下:

Thread-0--->10Thread-1--->10Thread-0--->9Thread-1--->9Thread-0--->8Thread-1--->8Thread-0--->7Thread-1--->7Thread-0--->6Thread-1--->6Thread-0--->5Thread-0--->4Thread-1--->5Thread-0--->3Thread-0--->2Thread-1--->4Thread-0--->1Thread-1--->3Thread-1--->2Thread-1--->1

  从结果中可以看出,两个线程都启动起来,并且交叉运行,但是这两个线程可以认为他们是不关联的,因为线程1和线程2各自拥有了新的num变量,即这两个线程不共享该变量。接下来看实现Runnable接口的多线程Demo。

实现Runnable接口

  上面已经看了Runnable接口的源码,直接上Demo。

public class ClassImplRunnable implements Runnable { private int num = 10; @Override public void run() { for (int i = 0; i < 10; i++) { if (num > 0) { // 因为Runnable中没有currentThread方法,所以要加上Thread System.out.println(Thread.currentThread().getName() + "--->" + num--); } } }}

  ClassImplRunnableClassExtendsThread代码几乎一样,不同的是实现了Runnable接口。测试代码如下:

public class DemoTest { public static void main(String[] args) { ClassImplRunnable classImplRunnable = new ClassImplRunnable(); new Thread(classImplRunnable).start(); new Thread(classImplRunnable).start(); }}

  这里的ClassImplRunnable只实现了Runnable接口,但是没有start方法,无法启动线程,但是Thread类中有个构造方法:

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

传入一个实现Runnable接口的类即可创建一个新的线程,然后调用start方法即可启动线程。注意启动线程只能用start方法,如果调用run方法,那么就只是执行了一个方法,并没有启动线程。   运行结果如下:

Thread-0--->10Thread-0--->8Thread-0--->7Thread-1--->9Thread-0--->6Thread-1--->5Thread-1--->3Thread-1--->2Thread-0--->4Thread-1--->1

  两个线程交叉运行,因为没有使用同步锁。同时,这里两个线程使用了同一个对象构造了Thread,所以其实两个线程运行的时候共享了num变量。   仔细回顾一下两次运行,发现继承Thread类的ClassExtendsThread类运行时,是直接创建了两个ClassExtendsThread对象,但是ClassImplRunnable类是创建了一个对象,但是创建了两个Thread对象并启动线程,那么就不能说继承Thread的类实现多线程不能共享资源,实现了Runnable接口的多线程才能共享资源。   接下里来模仿一下ClassImplRunnable类启动线程的方式,代码如下:

public class DemoTest { public static void main(String[] args) { ClassExtendsThread classExtendsThread = new ClassExtendsThread(); new Thread(classExtendsThread).start(); new Thread(classExtendsThread).start(); }}

  运行结果如下:

Thread-2--->10Thread-1--->9Thread-1--->7Thread-1--->6Thread-1--->5Thread-1--->4Thread-1--->3Thread-1--->2Thread-1--->1Thread-2--->8

  结果可以看出,其实是共享了资源(num)的。   这里线程名字变了,因为new了一个ClassExtendsThread对象的时候,就已经创建了一个线程,而后面调用Thread的构造函数又创建了两个线程,而且只启动了线程2和3,即Thread-1Thread-2。   今天下午查了一下午资料,也没有一个讲的清楚的好文章,最后灵光一闪,用Google搜了一下,结果直接搜出来两篇讲的很好的文章,一个是GitHub的,一个是博客园的,按道理说百度和必应都能搜出来的,但是。。。

总结

  用ThreadRunnable都可以实现多线程,但是一般情况下还是用实现Runnable接口的方法来实现多线程,原因有以下几点:   1. 因为Java的单继承特性,如果继承Thread的话就不能再继承其他类,而接口是可以实现多个的,所以实现Runnable接口更加灵活;   2. 关于很多文章提到的资源共享问题,继承了Thread类的类的对象,已经是一个线程了,是可以直接调用start方法来启动线程的,但是如果要实现类似于ClassImplRunnable这样的所谓的“资源共享”,还需要把对象传入Thread的构造函数重新实例化Thread对象,比较麻烦,所以还是用实现Runnable接口的方法便捷一点。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表