不要使用Integer对象作为锁对象,Integer对象改变,往往会生成一个新的对象,从而导致锁对象不唯一。
public class SynchronizedTest {
public static void main(String[] args) {
Thread why = new Thread(new TicketConsumer(10), "why");
Thread mx = new Thread(new TicketConsumer(10), "mx");
why.start();
mx.start();
}
}
class TicketConsumer implements Runnable {
private volatile static Integer ticket;
public TicketConsumer(int ticket) {
this.ticket = ticket;
}
/**
* 不用使用Integer作为锁对象
* 第一次竞争:锁的都为10
* 第一个线程执行完之后,释放了10,此时第二个线程等待被唤醒,获得9,开始执行操作
* 第一个线程此时加锁9,同样也获得9,开始执行操作
* 执行ticket--之后变成会生成新的Integer对象
* 解决方法为使Integer对象要唯一
*/
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "开始抢第" + ticket + "张票,对象加锁之前:" + System.identityHashCode(ticket));
synchronized (getSyncObject(ticket)) {
System.out.println(Thread.currentThread().getName() + "抢到第" + ticket + "张票,成功锁到的对象:" + System.identityHashCode(ticket));
if (ticket > 0) {
try {
//模拟抢票延迟
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了第" + ticket-- + "张票,票数减一");
} else {
return;
}
}
}
}
private ConcurrentHashMap<Integer, Integer> locks = new ConcurrentHashMap<>();
private Object getSyncObject(final Integer id){
// 保证锁对象唯一
locks.putIfAbsent(id, 1);
return locks.get(id);
}
}