线程安全问题
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。也可以说线程安全问题,是因为访问了共享的数据。
模拟一个卖票过程,假设总共有100张票,有三个售票员(开启三个线程)
public class SaleTickets implements Runnable { private int tickets = 100; @Override public void run() { // 让其不断的卖票 while(true) { // tickets必须大于0 if (tickets > 0) { // 取到票后,就休息10毫秒 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } // 打印出卖票信息 System.out.println(Thread.currentThread().getName() + "正在卖第" + tickets + "票"); // 票数实现-1 tickets--; } } } }
实现卖票
public class TestSale { public static void main(String[] args) { // 开启三个新线程,模拟三个售票员 SaleTickets st = new SaleTickets(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); Thread t3 = new Thread(st); t1.start(); t2.start(); t3.start(); } }
控制台打印出的结果:


发现同一张票100被卖出了三次甚至是卖出不存在的票0,这明显是错误的。这时就出现线程安全问题。
原因:
1.卖出三张100号的票,是因为三个线程同时执行了
System.out.println(Thread.currentThread().getName() + "正在卖第" + tickets + "票");
且三个都线程都执行了tickets--,所以就没有99、98,而是直接跳转到了97。即当Thread-1执行了上述语句后,CPU的使用权可能就被Thread-0抢夺了,当Thread-0执行了上述输出语句后,CPU的使用权可能就被Thread-2抢夺了。故同时输出了三个100号票,然后三个线程再依次执行tickets--;故tickets就从100直接跳到了97。
2.卖出了0号票,是因为当Thread-0获得CPU的使用权进入run()方法时,然后由于程序调用了sleep()方法,故Thread-0进入睡眠;此时Thread-1获得CPU的使用权,进入run()方法,然后又sleep()睡眠了,失去了CPU的使用权;此时,Thread-2获得CPU的使用权,进入run()方法,执行到sleep(),进入睡眠。然后Thread-0睡醒了,开始输出语句,并且执行tickets--;此时tickets=0,且0>0不成立,故Thread-0线程就退出了;故Thread-1此时获得CPU,开始输出语句,此时tickets=0,故输出了0号票。

浙公网安备 33010602011771号