上一讲中我们提到了继承Thread类是实现多线程的一种方式,那么现在就来看看第二种方式:Runnable接口。
废话少说,上代码(依旧是之前的例子):
public class ThreadDemoOne implements Runnable {
int no,workno,sleeptime;
public ThreadDemoOne(int no,int workno,int sleeptime) {
// TODO Auto-generated constructor stub
this.no = no;
this.workno = workno;
this.sleeptime = sleeptime;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
for(int i=0;i<5;i++){
System.out.println("Thread["+no+"] do work "+workno+"_"+i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
System.out.println("Main do work 1");
new Thread(new ThreadDemoOne(1,2,1000)).start();
System.out.println("Main do work 3");
Thread.sleep(1000);
System.out.println("Main do work 4");
new Thread(new ThreadDemoOne(2,5,1000)).start();
Thread.sleep(1000);
System.out.println("Main do work 6");
}
}
乍一看貌似一样啊,请仔细看(红色代码部分),是的,区别就是这么小!
有人就有疑问了,oracle是不是吃饱了撑的(sorry,骂错了,当时还是SUN公司推出的多线程),为什么好端端要提供两种差不多的多线程实现方式呢?
不着急骂Java脑残,我们先来看看两者的关系:
首先,我们发现Thread是个类,而Runnable是接口,但凡计算机科班出身,或者参加过java面试的同学,都能轻而易举的说出类和接口的联系和区别,其中最重要的一点就是,类无法多重继承,而接口可以实现多个。好了,这就是Thread和Runnable的区别之一。
其次,我们发现Runnable接口方法中没有start()方法,而多线程激活需要这个方法,但这个方法存在于Thread类中。也就是可以说,对于实现Runnable接口的子类,也需要依靠Thread的start()方法来启动多线程。
最后,通过JDK文档,我们发现Thread类实现Runnable接口,即在本质上,Thread类是Runnable接口的子类。
了解了以上几点,相信大家都明白了Thread离不开Runnable,因为Runnable是他老子,而实现Runnable接口的子类也离不开Thread,因为要靠Thread来启动多线程,环环相扣,惺惺相惜,可昭日月~~
看完上面这段刻骨铭心的互相依赖关系,我们还是要写个观后感:建议读书者尽可能的使用Runnable接口去实现多线程机制,这样既可以避免了类的单继承局限,也可以使方法和启动解耦,而且也适合于资源共享!
等等,资源共享?上面没提到这个啊,这到底怎么回事?
对了,忘记说了,哈哈!我们还是来看代码吧,来个经典的12307-1关注的卖票问题,目前手头就五张票,要三个窗口一起卖,分别采用Thread和Runnable的方式:
public class SellTicket extends Thread {
private int ticket = 5;//实际只有五张票
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<100;i++){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+" sell ticket["+ticket--+"]");
}
}
}
public static void main(String[] args) {
//实例化了三个卖票对象,实际是各卖各的票,猜猜总共卖出去几张?
new SellTicket().start();
new SellTicket().start();
new SellTicket().start();
}
}
public class SellTicket implements Runnable {
private int ticket = 5;//实际只有五张票
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<100;i++){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+" sell ticket["+ticket--+"]");
}
}
}
public static void main(String[] args) {
//只实例化了一个卖票对象,实际是三个线程一起卖票,猜猜总共卖出去几张?
SellTicket st = new SellTicket();
new Thread(st).start();
new Thread(st).start();
new Thread(st).start();
}
}
这就是Runnable的共享资源的好处,今天就到这,洗洗睡了~