线程安全处理的3种方式
一、模拟电影院的卖票过程。假设要播放的电影是 “唐人街探案3”,本次电影的座位共100个(本场电影只能卖100张票)。
代码如下:
public class Tickects implements Runnable { private int ticket=100; public void run() { //int ticket=100 自己独有数据 不是共享数据 所以int ticket=100不能写到这个地方 while(true){ if(ticket>0){ try { Thread.sleep(500); //这个地方加sleep睡眠状态 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票"); } } } }
public class Demo01 { public static void main(String[] args) { //创建线程任务 Tickects t=new Tickects(); //创建线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); t1.start(); t2.start(); t3.start(); }
运行结果如下:
出现的问题:出现重复票 错误票0
解决方法:①同步代码块 使用 synchronized 关键字 (锁对象){可能出现问题的代码}
public class Tickects02 implements Runnable { private int ticket=10; private Object obj=new Object(); public void run() { while(true){ synchronized (obj) { //还可以直接用this 结果是一样的 //可能发生问题的代码块问题代码 if(ticket>0){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票"); } } } } } public class Demo02 { public static void main(String[] args) { //创建线程任务 Tickects02 t=new Tickects02(); //创建线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); t1.start(); t2.start(); t3.start(); } }
② 同步方法
public synchronized void method(){
可能会产生线程安全问题的代码
}
public class Tickects03 implements Runnable { private int ticket=100; public void run() { while(true){ sale(); //调用下面这个sale()对象 } } //同步方法(内置锁对象this) public synchronized void sale(){ if(ticket>0){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票"); } } } public class Demo03 { public static void main(String[] args) { //创建线程任务 Tickects03 t=new Tickects03(); //创建线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); t1.start(); t2.start(); t3.start(); } }
③用Lock 接口
public class Tickects04 implements Runnable { private int ticket=100; //lock 接口实现类对象 private Lock lock=new ReentrantLock(); public void run() { while(true){ lock.lock(); if(ticket>0){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票"); } //释放锁 lock.unlock(); } } } public class Demo04 { public static void main(String[] args) { //StringBuffer和StringBuilder //StringBuffer 速度慢安全 (慢:线程同步) //StringBuilder 速度快 不安全 比较适合单线程 //创建线程任务 Tickects04 t=new Tickects04(); //创建线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); t1.start(); t2.start(); t3.start(); } }
这三种方法打印出结果是相同的:
无重复,无错误票;
欢迎各位大神指点和评论,多多交流;