Java语言学习总结 扩展篇 线程安全问题的出现及解决办法

线程安全

当多个线程同时分别执行同一个线程时,可能出现安全问题。比如电影院三个售票窗口,同时开始售同样的100张票,就可能出现两个窗口同时售同一张票,或者某个窗口售卖不存在的票的问题。
代码示例:

public class ThreadSafeClass implements Runnable{
	public int ticket=100;

	@Override
	public void run() {
		while(ticket>0) {
			System.out.println(Thread.currentThread().getName() + "第 "+ ticket+"张票");
			ticket--;
		}
	}

}
public class ThreadSafeTest {

	public static void main(String[] args) {
		ThreadSafeClass ts = new ThreadSafeClass();
		
		Thread t0 = new Thread(ts);
		Thread t1 = new Thread(ts);
		Thread t2 = new Thread(ts);
		t0.start();
		t1.start();
		t2.start();
	}
}

输出结果:
输出结果
可见前三次就输出了同样的第100张票。 即第100张票被重复卖了。这就出现了线程安全问题。

这里针对前面四次输出进行分析。
当t0,t1,t2三个线程同时开始执行,并且同时执行到System.out.println,此时ticket还等于100,并且没有来得及进行自减。 所以t0和t2都输出了第100张票。而t1显然输出速度明显慢于t0和t2。

解决线程安全问题

运行线程的同步技术来解决线程安全问题。
同步代码块synchroized
针对卖票案例出现的线程安全问题, 卖出了不存在的票和重复的票
解决线程安全问题的一种方案:使用同步代码块
格式:
synchronized(锁对象){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注意:
1.通过代码块中的锁对象,可以使用任意的对象
2.但是必须保证多个线程使用的顾对象是同一个
3.锁对象作用:
把同步代码块锁住,只让-一个线程在同步代码块中执行
对刚才的售票代码进行如下修改

public class ThreadSafeClass implements Runnable{
	public int ticket=100;

	//创建一个锁对象
	Object obj = new Object();
	
	//创建一个线程任务,卖票
	@Override
	public void run() {
		while(ticket>0) {
			synchronized(obj) {
				System.out.println(Thread.currentThread().getName() + "第 "+ ticket+"张票");
				ticket--;
			}
		}
	}

}

第二种方法 同步方法
解决线程安全问题的二种方案:使用同步方法
使用步骤:

  1. 把访问了共享数据的代码抽取出来,放到一个方法中
  2. 在方法上添加synchronized修饰符
    格式:定义方法的格式
    修饰行 synchronized 近回值类型方法名(参数列表){
    可能会出现线程安全问题的代码(访问了共享数据的代码)
    }
发布了72 篇原创文章 · 获赞 3 · 访问量 6179

猜你喜欢

转载自blog.csdn.net/Ace_bb/article/details/104181388
今日推荐