两周的小暑假也算是过完了,接下来得好好做东西了,博客从今天开始也要跟上进度了。
1. 两种创建的方式
1 继承Thread类,并且重写其中的run()方法
2 实现Runnable接口,重写其中的run()方法
但是在实现应用时,我们多用实现Runnable接口的方式,这是因为Java的单继承多实现的机制,这样一来就可以避免由于这个机制代码的局限性。其实我们用Runnable的原因不止于此,最主要的一点是Runnable是可以进行数据共享的,但因此它也是线程不安全的。现在对这两点进行逐一解释,我们首先通过一个老生常谈的售票的例子,对数据共享这一点进行解释。
2. 示例代码
示例代码1
首先我们看一下我们自己定义一个MyThread,让它继承Thread,然后我们定义一个count,这个count参数可以想象成我们要共享的资源。然后代码就很简单了,如下:
1 | public class TestThread { |
运行结果1:
我们先将两个代码都给大家,稍后再做分析。
示例代码2
同样,我们定义一个内部类,让它实现Runnable接口,代码如下:
1 | public class testRunnable { |
运行结果2:
3. 分析
通过代码运行结果我们不难看出,这两种方法的截然不同,相信大家现在也能理解了,为什么说Runnable是可以进行资源共享的,不过还是在多说一点吧。
我们继承了Thread的MyThead类,通过三次实例化,分别的将这三个再start起来,就相当于给了三个售票窗口每人一个卖5张票的任务,他们因为是三个实例,各自做各自的事情,各自完成这个卖票的任务。
而我们实现了Runnable的MyThread类,相当于先创建了一个任务(其实就是我们new MyThread过程),然后通过实例化三个Thread,创建了三个线程共同去完成这个任务。
那为什么说Runnable是线程不安全的呢,理由其实很简单:如果我们在System.out…之前加上一个线程休眠操作的话,就会很有可能导致我们的count最后能输出-1,也就是说存在一张票被售卖两次的状况。如果想对于这一点进行测试的话,大家要注意一点,票数要设置的大一些,休眠时间写成1毫秒就行,这样的测试效果比较明显。
那么如何才能保证我们用Runnable时的线程安全性呢?思路很简单,就是我们需要在这个地方加上同步操作(互斥锁),确保在同一时刻只有一个线程在执行售票的操作。而我们之前的继承Thread的方法并不需要这么做,原因就是每个线程执行自己的Thread对象中的代码,不存在多个线程共同执行同一个方法的情况。
以上是本次的所有内容,感谢驻足~