- 之所以造成这个误解,大概跟线程安全的几种解决手段有关.
目前公认的几种线程安全的解决手段:
- 同步技术
- 多用方法内局部变量
- ThreadLocal技术(一线程,一实例变量copy)
除同步技术外,另两种解决手段都是"anti_sharing",实际是牺牲了多并发线程下的资源的共享特性.
多线程的共享资源的实际值会和理论值不一致,这样就叫作"线程不安全" 而多线程对共享资源的改变,也是理论值之一.即理论上是接受共享资源被多个线程改变的.
我们举最常见的"多线程售票"的例子,很多人在学习多线程都是从这个例子开始的. 下面这段程序是存在线程安全问题的,但"共享售票"并不意味着线程不安全
public class MyThread implements Runnable { private int ticket = 5; // 一共才5张票,会被多线程共同卖出
public void run() { for (int i = 0; i < 50; i++) { if (this.ticket > 0) { System.out.println("卖票:ticket = " + this.ticket--); } } } }
public static void main(String[] args) { MyThread mt = new MyThread(); // 单实例 new Thread(mt).start() ; // 一个线程开始卖票 new Thread(mt).start() ; // 另一个线程开始卖票 new Thread(mt).start() ; // 再一个线程开始卖票 }
|
执行: 卖票:ticket = 5 卖票:ticket = 4 卖票:ticket = 3 卖票:ticket = 2 卖票:ticket = 1
| 因为程序执行太快了,来不及显性产生线程安全问题,我们在run()中加一个Thread.sleep(300)方法
public void run() { for (int i = 0; i < 50; i++) { if (this.ticket > 0) { try { Thread.sleep(300);// 延迟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("卖票:ticket = " + this.ticket--);
|
运行结果如下: D:\java\source\thread\sync>java syndemo.SynDemo01 卖票:ticket = 5 卖票:ticket = 4 卖票:ticket = 3 卖票:ticket = 2 卖票:ticket = 1 卖票:ticket = 0 卖票:ticket = -1 这就是理论值(this.ticket > 0)与实际值(-1)不符, 反映了线程安全的概念定义
| 原因: 当剩最后一张票时 上一个进程通过了(this.ticket > 0)的判断,却sleep了,没来得及把this.ticket-- 而另一个进程趁机也通过了(this.ticket > 0)的判断 这样就形成了ticket=1时两个线程都通过测试,都进行了--,就出现了-1
|