多线程(三)线程安全问题

1.什么是线程安全?

我们思考这么一个问题,假设有一部电影正在卖票,一共100张,用户即可以在app中购买,也可以在官网购买,也可以线下购买,那么有没有可能一个用户正在app买最后一张票,同时又有个人在官网购买,又有人在线下购买,这样就出现了多线程中的线程安全问题。我们来实例化下。

1.创建任务

 1 public class Ticket implements Runnable {
 2     private int ticket=100;
 3     @Override
 4     public void run() {
 5         // TODO Auto-generated method stub
 6         while(true){
 7             if(ticket>0){
 8                 try {
 9                     Thread.sleep(50);//略微增加等待时间,表现实例
10                 } catch (InterruptedException e) {
11                     // TODO Auto-generated catch block
12                     e.printStackTrace();
13                 }
14                 System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket--+"张票");
15             }
16         }
17     }
18 }

2.创建任务对象,执行任务

 1 public class demo01 {
 2     public static void main(String[] args) {
 3         //创建线程任务
 4         Ticket r = new Ticket();
 5         //创建线程对象
 6         Thread t1 = new Thread(r);
 7         Thread t2 = new Thread(r);
 8         Thread t3 = new Thread(r);
 9         //开启线程
10         t1.start();
11         t2.start();
12         t3.start();
13     }
14 }

执行结果:

这就是问题所在,那么该如何解决这个问题?

2. 同步代码块

 在使用是,要保证锁对象的唯一性。

实际代码更改后

 1 public class Ticket01 implements Runnable {
 2     private int ticket=100;
 3     private Object obj = new Object();
 4     @Override
 5     public void run() {
 6         // TODO Auto-generated method stub
 7         while(true){
 8             //同步代码块
 9             synchronized (obj) {
10                 if(ticket>0){
11                     try {
12                         Thread.sleep(50);
13                     } catch (InterruptedException e) {
14                         // TODO Auto-generated catch block
15                         e.printStackTrace();
16                     }
17                     System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket--+"张票");
18                 }
19             }
20         }
21     }
22 }

3.同步方法

实际代码更改

 1 public class Ticket02 implements Runnable {
 2     private int ticket=100;
 3     @Override
 4     public void run() {
 5         // TODO Auto-generated method stub
 6         while(true){
 7             sale();
 8         }
 9     }
10     public synchronized void sale(){
11         if(ticket>0){
12             try {
13                 Thread.sleep(50);
14             } catch (InterruptedException e) {
15                 // TODO Auto-generated catch block
16                 e.printStackTrace();
17             }
18             System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket--+"张票");
19         }
20     }
21 }

4.Lock接口

使用Lock接口,我们可以更广泛的锁定操作。

实际代码更改

 1 public class Ticket03 implements Runnable {
 2     private int ticket=100;
 3     private Lock lock = new ReentrantLock();
 4     @Override
 5     public void run() {
 6         // TODO Auto-generated method stub
 7         while(true){
 8             lock.lock();
 9             if(ticket>0){
10                 try {
11                     Thread.sleep(50);
12                 } catch (InterruptedException e) {
13                     // TODO Auto-generated catch block
14                     e.printStackTrace();
15                 }
16                 System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket--+"张票");
17             }
18             lock.unlock();
19         }
20     }
21 }
原文地址:https://www.cnblogs.com/shenhx666/p/15061998.html