小坑集锦 – Java

坑无处不在, 防不胜防, 吾辈诚惶诚恐, 战战兢兢.

synchronized(String)/synchronized(int)

synchronized关键字添加到实例属性中是给实例中的属性加锁, 但是当被锁属性会跨实例存在时, 加锁就会出现意想不到的情况:


public class SyncTest {

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    static class MyRunnable implements Runnable {
        private String s = "abc";
        private Object o = new Object();
        private Integer i = 10;
        private Integer iHuge = 10000000;
        @Override
        public void run() {
            synchronized (s) { // o, i, iHuge
                try {
                    Thread.sleep(1000);
                    System.out.println("Time:" + 
                       simpleDateFormat.format(new Date()));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String [] args) {
        for (int i = 0; i < 5; i++) {
            new Thread(new MyRunnable()).start();
        }
    }
}

上面这段代码做的事情是, 让每个线程尝试获取自己的Runnable实例属性的锁, 得到锁并持锁睡眠1秒后打印当前时间, 退出.
如果实例属性锁不会跨实例共享时, 每个线程应该几乎同时完成休眠1秒之后, 同时打印出相同的时间. 比如这里的oiHuge
但如果实例属性被多实例共享, 同一时间就只能有一个实例持有锁, 那么打印的时间应该是每隔秒打印一次. 比如这里的si, s字符串是由于它在字符串常量池中保存; 而在-128~127范围内的int, 会被Integer的静态内部类IntegerCache缓存为对应的Integer对象, 每次使用到这些数值的对象事, 直接返回相同的对象引用.

发表评论

电子邮件地址不会被公开。

80 ÷ = 8