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 }