我们之前写了个模拟银行排队叫号的demo,这里为了说明问题我把代码稍加改造:
public class TicketWindowRunnable implements Runnable {
private int index = 1;
private static final int MAX = 500;
@Override
public void run() {
while (true) {
if (index >= MAX)
break;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 的号码是:" + (index++));
}
}
}
运行效果如下:
可以看到我们的运行结果竟然出现了501,其实这个是因为线程同步问题导致的,这在我们并发中经常提到,类似的比如商品超卖等都并发中同时读了数据,然后做了操作。我们来引入synchronized试一下:
public class TicketWindowRunnable implements Runnable {
private int index = 1;
private static final int MAX = 500;
private final Object MOINTOR = new Object();
@Override
public void run() {
while (true) {
synchronized (MOINTOR){
if (index >= MAX)
break;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 的号码是:" + (index++));
}
}
}
}
运行效果如下:
synchronized 它可以把任意一个非 NULL 的对象当作锁。他属于独占式的悲观锁,同时属于可重
入锁。
Synchronized 作用范围
作用于方法时,锁住的是对象的实例(this);
当作用于静态方法时,锁住的是Class实例,又因为Class的相关数据存储在永久带PermGen(jdk1.8 则是 metaspace),永久带是全局共享的,因此静态方法锁相当于类的一个全局锁,会锁所有调用该方法的线程;
synchronized 作用于一个对象实例时,锁住的是所有以该对象为锁的代码块。它有多个队列。
更多细节我们后续再学习。
原文:https://www.cnblogs.com/stormsquirrel/p/13619052.html