本文共 2323 字,大约阅读时间需要 7 分钟。
本来想写一个程序,模拟12306抢票,但是最后发现Synchronized锁不住Integer,记录一下。
public class TicketConsumer implements Runnable{ private Integer i; public TicketConsumer(int i) { super(); this.i = i; } @Override public void run() { while(true) { synchronized (i) { if(i>0) { try { Thread.sleep(100); // 模拟抢票延迟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了第"+i--+"张票"); }else { return; } } } }}
public class Test1 { public static void main(String[] args) { TicketConsumer ticket = new TicketConsumer(new Integer(10)); Thread t1 = new Thread(ticket,"张三"); Thread t2 = new Thread(ticket,"李四"); t1.start(); t2.start(); }}
大眼一瞟,似乎没问题,但是运行就出了问题,两人抢到了同一张票
运行结果 |
---|
张三抢到了第10张票李四抢到了第9张票 张三抢到了第9张票 李四抢到了第8张票 李四抢到了第7张票 张三抢到了第6张票 李四抢到了第5张票张三抢到了第4张票 李四抢到了第4张票 张三抢到了第3张票 张三抢到了第2张票 李四抢到了第1张票 |
原因就是,Integer取值如果是在[-128,127]之间,系统会从常量池中取值,如果超出这个范围,系统会自动new一个新对象,所以每次对象都不一样
Integer i = 1;System.out.println(System.identityHashCode(i));System.out.println(System.identityHashCode(++i));StringBuilder sb = new StringBuilder("张三");System.out.println(System.identityHashCode(sb));sb.append("李四");System.out.println(System.identityHashCode(sb));
运行结果 |
---|
366712642 1829164700 2018699554 2018699554 |
Integer在自增后,内存地址就变了,而StringBuilder却不会变,一旦变化Synchronized每次锁的就不是同一个对象,所以锁不住。
解决办法:
可以把Integer单独放到一个类中,Synchronized这个类的对象,就可以了
public class Ticket { int count; public Ticket(int count) { super(); this.count = count; } }
public class TicketConsumer implements Runnable{ private Ticket ticket; public TicketConsumer(Ticket ticket) { super(); this.ticket = ticket; } @Override public void run() { while(true) { try { Thread.sleep(100); // 模拟抢票延迟 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (ticket) { if(ticket.count>0) { System.out.println(Thread.currentThread().getName()+"抢到了第"+ticket.count--+"张票"); }else { return; } } } }}
public class Test1 { public static void main(String[] args) { TicketConsumer ticket = new TicketConsumer(new Ticket(10)); Thread t1 = new Thread(ticket,"张三"); Thread t2 = new Thread(ticket,"李四"); t1.start(); t2.start(); }}
运行结果 |
---|
李四抢到了第10张票 张三抢到了第9张票 张三抢到了第8张票 李四抢到了第7张票 张三抢到了第6张票 李四抢到了第5张票 李四抢到了第4张票 张三抢到了第3张票 张三抢到了第2张票 李四抢到了第1张票 |
O了…
转载地址:http://mcsnb.baihongyu.com/