对项目中遇到的Synchronized 失效情况做出如下总结
- Integer 问题
比如抢票问题,是一个模拟抢票的过程,一共 10 张票,开启两个线程去抢票。票是共享资源,且有两个线程来消费,所以为了保证线程安全,TicketConsumer 的逻辑里面用了 synchronized 关键字。
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;
}
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "开始抢第" + ticket + "张票,对象加锁之前:" + System.identityHashCode(ticket));
synchronized (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;
}
}
}
}
}
我们确实证明了 synchronized 没有生效的原因是锁发生了变化。可以采用class 用对象管理 或者Map将数字装入Map中,无论数字变为多少,锁访问的对象都不会改变。所以可以用class或者Map装这个锁。
- 事物问题
1.在spring的事务中使用synchronized,会导致锁失效的:
底层的原因是如下的:transaction方法的调用对象是当前对象的代理对象,而synchronized对应的锁定的是当前对象的,两者完全不是同样的一个对象的,所以,此时transaction对应的是失效的。