本文共 2482 字,大约阅读时间需要 8 分钟。
多线程在共同操作一个变量的时候可能会产生问题,这个我们在之前的多个线程卖票案例中也给大家提到过,那么我们今天就来解决一下这个问题。会用到一个关键字synchronized,如下:
/** * 多个线程买票:安全 */public class UnsafeBuyTicket implements Runnable { //定义总票数 private int ticketNum=10; //定义标记 private boolean flag=true; //重写的run方法 @Override public void run() { //如果标记为true,则调用买票方法 while (flag){ buyTicket(); } } //synchronized:锁 //线程安全实现机制:队列+锁 private synchronized void buyTicket() { //判断票数是否小于等于0,如果票数小于等于0则将标记改为false if (ticketNum<=0){ flag=false; //return结束方法 return; } try { //模拟网络延迟 Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } //打印票数 System.out.println(Thread.currentThread().getName()+"买到了第"+(ticketNum--)+"张票"); } //主方法,开启三个线程操作一个对象 public static void main(String[] args) { UnsafeBuyTicket unsafeBuyTicket = new UnsafeBuyTicket(); new Thread(unsafeBuyTicket,"小明001").start(); new Thread(unsafeBuyTicket,"小方002").start(); new Thread(unsafeBuyTicket,"小杭003").start(); }}
那么为什么用了synchronized这个关键字就会安全了,线程安全的实现机制就是队列+锁,我们在一个线程进入操作数据的时候,其他线程在外面排队等候,并将这个数据锁起来,就不会产生线程不安全了。
再看以下案例:
public class SafeList { public static void main(String[] args) throws InterruptedException { ArrayListlist = new ArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ list.add("1"); }).start(); } for (int i = 5; i > 0; i--) { Thread.sleep(1000); System.out.println("倒计时"+i); } System.out.println(list.size()); }}
输出:
倒计时5倒计时4倒计时3倒计时2倒计时19999
我们发现本来集合的大小因该是10000,但是最后却输出的是9999.那么我们给线程加上锁试试:
public class SafeList { public static void main(String[] args) throws InterruptedException { ArrayListlist = new ArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ //我们知道是因为list添加数据线程不安全的,那么我们在这里用同步代码块将其锁住即可 synchronized (list){ list.add("1"); } }).start(); } for (int i = 5; i > 0; i--) { Thread.sleep(1000); System.out.println("倒计时"+i); } System.out.println(list.size()); }}
输出:
倒计时5倒计时4倒计时3倒计时2倒计时110000
同步代码块默认锁住的是this,我们视情况而定,看是哪个会发生资源的共用,分析是哪里导致线程不安全就锁住哪里。
有同步代码块就有同步方法,同步方法只能锁住的是this,就比如上面的卖票案例,就是利用的是同步方法。转载地址:http://faiwi.baihongyu.com/