JAVA多线程之Runnable和Thread比较

来源:互联网 发布:java句柄是什么意思 编辑:程序博客网 时间:2024/06/06 07:41

在我们开发的过程中常常会碰到多线程的问题,对于多线程的实现方式主要有两种:实现Runnable接口、继承Thread类。对于这两种多线程的实现方式也是有着一些差异。既然实现了多线程那必然离不开管理这些线程,当问题比简单时一个或者几个线程就OK了,也涉及不到效率问题。一旦线程数量多起来的时候,必然躲不过这些线程的创建与销毁,而往往这是很浪费时间的。这时就需要利用线程池来进行管理,既免去了我们创建线程和销毁线程的代码,也提高了程序的效率。下面针对以上问题做出相关讲解。

一、Runnable、Thread比较

首先阐述实现Runnable的好处:

  • java不允许多继承,因此实现了Runnable接口的类可以再继承其他类。
  • 方便资源共享,即可以共享一个对象实例???(从很多博客中看到这样描述,但是此处有疑问,例子如下)

下面来通过具体代码来解释上述优点,网上很流行的买票系统,假设有10张票,首先通Thread来进行购买。代码如下:

public class TicketThread extends Thread{    private int ticket = 10;    public void run(){        for(int i =0;i<10;i++){            synchronized (this){                if(this.ticket>0){                    try {                        Thread.sleep(100);                        System.out.println(Thread.currentThread().getName()+"卖票---->"+(this.ticket--));                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }    }    public static void main(String[] arg){        TicketThread t1 = new TicketThread();        new Thread(t1,"线程1").start();        new Thread(t1,"线程2").start();        //也达到了资源共享的目的,此处网上有各种写法,很多写法都是自圆其说,举一些特殊例子来印证自己的观点,然而事实却不尽如此。    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

输出: 
线程1卖票—->10 
线程1卖票—->9 
线程1卖票—->8 
线程2卖票—->7 
线程2卖票—->6 
线程1卖票—->5 
线程1卖票—->4 
线程2卖票—->3 
线程2卖票—->2 
线程1卖票—->1

实现Runnable接口:

package threadTest;public class TicketRunnable implements Runnable{    private int ticket = 10;    @Override    public void run() {        for(int i =0;i<10;i++){            //添加同步快            synchronized (this){                if(this.ticket>0){                    try {                        //通过睡眠线程来模拟出最后一张票的抢票场景                        Thread.sleep(100);                        System.out.println(Thread.currentThread().getName()+"卖票---->"+(this.ticket--));                    } catch (Exception e) {                        e.printStackTrace();                    }                }            }        }    }    public static void main(String[] arg){        TicketRunnable t1 = new TicketRunnable();        new Thread(t1, "线程1").start();        new Thread(t1, "线程2").start();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

输出: 
线程1卖票—->10 
线程1卖票—->9 
线程1卖票—->8 
线程1卖票—->7 
线程2卖票—->6 
线程2卖票—->5 
线程2卖票—->4 
线程2卖票—->3 
线程2卖票—->2 
线程2卖票—->1

从这两个例子可以看出,Thread也可以资源共享啊,为什么呢,因为Thread本来就是实现了Runnable,包含Runnable的功能是很正常的啊!!至于两者的真正区别最主要的就是一个是继承,一个是实现;其他还有一些面向对象的思想,Runnable就相当于一个作业,而Thread才是真正的处理线程,我们需要的只是定义这个作业,然后将作业交给线程去处理,这样就达到了松耦合,也符合面向对象里面组合的使用,另外也节省了函数开销,继承Thread的同时,不仅拥有了作业的方法run(),还继承了其他所有的方法。综合来看,用Runnable比Thread好的多。

针对本例再补充一点,在以上程序中,如果去掉同步代码块,则会出现其中一人购买第0张票的情况,所以我们在做多线程并行的时候一定要时刻考虑到边界值的问题,在关键代码处必须要做好同步处理