synchronized踩坑

2017-07-25  本文已影响85人  忘净空

不要使用字符串常量作为对象锁去同步代码

synchronized是对象锁,但是对于这个Java内置的对象锁如果理解不深入可能就会踩到坑。请看下面的例子:

public class DeadLockDemo {

    private static String A = "A";
    private static String B = "B";

    public static void main(String[] args) {

            new DeadLockDemo().deadLock();
    }

    private void deadLock() {
            Thread t1 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                            synchronized (A) {
                                    try { Thread.currentThread().sleep(2000);
                                    } catch (InterruptedException e) {
                                            e.printStackTrace();
                                    }
                                    synchronized (B) {
                                            System.out.println("1");
                                    }
                            }
                    }
            });

            Thread t2 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                            synchronized (B) {
                                    synchronized (A) {
                                            System.out.println("2");
                                    }
                            }
                    }
            });

            t1.start();
            t2.start();
    }

}

上面是一个死锁的例子,用来演示死锁是没有问题,但是大家有没有注意privat static String A = "A",它使用字符串常量作为对象锁,大家认为这个有问题吗?请看下面这个例子。

public class NotifyTest {

    private String flag = "true";

    class NotifyThread extends Thread {
        public NotifyThread(String name) {
            super(name);
        }

        public void run() {
            try {
                sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (flag) {
                //flag的对象变为false,对象发生改变
                flag = "false";
                flag.notifyAll();
            }
        }
    }

    class WaitThread extends Thread {
        public WaitThread(String name) {
            super(name);
        }

        public void run() {
            synchronized (flag) {
                while (flag.equals("true")) {
                    System.out.println(getName() + " begin waiting!");
                    long waitTime = System.currentTimeMillis();
                    try {
                        flag.wait();

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    waitTime = System.currentTimeMillis() - waitTime;
                    System.out.println("wait time :" + waitTime);
                }
                System.out.println(getName() + " end waiting!");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Main Thread Run!");
        NotifyTest test = new NotifyTest();
        NotifyThread notifyThread = test.new NotifyThread("notify01");
        WaitThread waitThread01 = test.new WaitThread("waiter01");
        notifyThread.start();
        waitThread01.start();
    }

}

运行结果:
Main Thread Run!
waiter01 begin waiting!
Exception in thread "notify01" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at juc.NotifyTest$NotifyThread.run(NotifyTest.java:24)

为什么会出现上面的情况:问题主要是flag对象的引用发生了改变,我们如何选择synchoronize的锁呢,其实只要我们将flag换为javaBean就行,现在为了方便起见我们使用String数组private String flag[] = {"true"}这样也可以解决问题。例子如下:

package juc;

/**
 * Created by wjk on 2017/7/25.
 */
public class NotifyTest {

    private String flag[] = {"true"};

    class NotifyThread extends Thread {
        public NotifyThread(String name) {
            super(name);
        }

        public void run() {
            try {
                sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (flag) {
                //flag的对象变为false,对象发生改变
                flag[0] = "false";
                flag.notifyAll();
            }
        }
    }

    class WaitThread extends Thread {
        public WaitThread(String name) {
            super(name);
        }

        public void run() {
            synchronized (flag) {
                while (flag[0].equals("true")) {
                    System.out.println(getName() + " begin waiting!");
                    long waitTime = System.currentTimeMillis();
                    try {
                        flag.wait();

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    waitTime = System.currentTimeMillis() - waitTime;
                    System.out.println("wait time :" + waitTime);
                }
                System.out.println(getName() + " end waiting!");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Main Thread Run!");
        NotifyTest test = new NotifyTest();
        NotifyThread notifyThread = test.new NotifyThread("notify01");
        WaitThread waitThread01 = test.new WaitThread("waiter01");
        notifyThread.start();
        waitThread01.start();
    }

}
上一篇 下一篇

猜你喜欢

热点阅读