上一篇总结了一些基本的概念,下面我们正式进入具体的操作阶段。
非常常见的一个问题,很多都会问,不过大部分都会回答:继承Thread类和实现Runnable接口,然后重写run方法。
我们先抛出1个问题,继承Thread类和实现Runnable方法创建线程的区别在哪儿?
一、创建方式1:继承Thread类
我们先看看thread这个类,多的没看,我们发现,他是实现的Runable接口。
具体实现
结果:
这里需要注意一下:
start()方法才是启动线程,不过这个“启动”并不是真正的启动,而是将线程置于“就绪”状态,由CPU去执行调度,当CPU分配了该任务的时间分片后,才是真正运行的时候;而直接调用run()方法并没有真正的启动线程,而是通过主线程去运行的,跟一个普通方法没有区别。这里大家可以尝试下将start()方法改成直接调用run()方法看看效果。
结果:
一、创建方式2:实现Runnable接口
我们还是先看看Runable这个接口
发现只有一个抽象的run()方法,我们接着看代码
其实从这里我们就可以发现,实现Runnable的方式依然采用的是Thread中是start()方法进行线程的启动;回到最初的那个问题,他们的区别到底是什么呢?其实他们本质上都是创建一个没有返回值的线程,不管是实现Runnable接口还是集成Thread类,都会使用new Thread的方式来创建线程对象,调用start()方法;只是在写法上有区别?如果问大家常用的,肯定会说实现Runnable接口,我记得我们老师也说话,Java提倡接口编程,方便扩展;但是这里,还有一个比较关键的区别,那就是Runnbale更容易实现资源共享(synchronized)!往下看代码,我们以一个卖票的实例说明下
运行结果:
(⊙o⊙)…其实,不知道大家有没有发现,Runnabel能够实现资源共享原因在于我们在调用的时候是把同一个对象t的实例扔进去的,再通过同步锁来实现的资源共享;而Thread在我们的前面示例中调用start()的方法是新建的2个实例对象,当然共享不了。
所以,最终要问他们2个有啥区别,(⊙o⊙)…写法区别以及实现关系上的区别!
当然创建方式还有其他的方式,比如实现callable接口,重写call方法,这个在后续我们利用一个redis的乐观锁结合业务再介绍实现。