线程安全问题以及解决方法

什么是线程安全问题?

我们通过代码来了解一下,下面是一个模拟卖票的案例,
首先我们先定义一个票Ticked类实现Runnable接口:

class Ticket implements Runnable{int ticked = 50;//一共50张票@Overridepublic void run() {while (true) {if(ticked > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}ticked--;System.out.println("卖了一张票,还剩" + ticked + "张票");}else{System.out.println("票已售罄!");break;}}}
}

然后定义一个测试类:模拟三个窗口卖票

public class Test1 {public static void main(String[] args) {Ticket ticket = new Ticket();Thread t1 = new Thread(ticket,"窗口一");Thread t2 = new Thread(ticket,"窗口一");Thread t3 = new Thread(ticket,"窗口一");t1.start();t2.start();t3.start();}
}

运行一下看效果:
在这里插入图片描述
可以看到我们的余票有两次剩余两张,还出现了余票为负数的情况,这就是线程安全问题,那么为什么会出现线程安全问题呢?

这是因为:多线程操作共享数据时,导致共享数据出错。

那么怎么解决这个问题呢?
有三种方法:

  • 同步代码块
  • 同步方法
  • Lock锁

我们先看第一种:使用同步代码块
只需要将操作共享数据的代码放在 synchronized 里面就可以了

class Ticket implements Runnable{int ticked = 50;@Overridepublic void run() {while (true) {synchronized (""){//这里小括号里面放的是 锁 对象,任何对象都可以是锁,但这个对象要是唯一的if(ticked > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}ticked--;System.out.println("卖了一张票,还剩" + ticked + "张票");}else{System.out.println("票已售罄!");break;}}}}
}

同步锁是谁?
对于非 static 方法,同步锁就是 this
对于 static 方法,我们使用当前方法所在类的字节码对象(类名.class)

再来看一下运行结果:完全没有问题
在这里插入图片描述
第二种:将操作共享数据的代码抽取出来放到一个方法里面就可以了

class Ticket implements Runnable{int ticked = 50;@Overridepublic void run() {while (true) {sellTicked();}}private synchronized void sellTicked() {if(ticked > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}ticked--;System.out.println("卖了一张票,还剩" + ticked + "张票");}}
}

运行看效果:是不是也完全没问题
在这里插入图片描述
第三种:使用Lock锁,用法其实与第一种差不多,我们看代码:

提示:这里讲一下Lock的两个方法:

  • public void lock() :加同步锁。
  • public void unlock() :释放同步锁。
class Ticket implements Runnable{int ticked = 50;Lock lock = new ReentrantLock();@Overridepublic void run() {while (true) {lock.lock();if(ticked > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}ticked--;System.out.println("卖了一张票,还剩" + ticked + "张票");}else{System.out.println("票已售罄!");break;}lock.unlock();}}
}

运行看效果:完全没问题
在这里插入图片描述


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部