1. 程式人生 > >17、使用synchronized(string)同步塊時,要注意String常量池帶來的例外

17、使用synchronized(string)同步塊時,要注意String常量池帶來的例外

導語:我們在使用synchronized(string)同步塊時,要注意String常量池帶來的例外。

在jvm中具有String常量池快取的功能。

package com.demo1;

public class Run {
    public static void main(String[] args) {
        String a = "a";
        String b = "a";
        System.out.println(a == b);
    }
}

列印結果:

true

下面的例子,將說明String常量池帶來的例外

package com.demo1;

public class MyObject {
    public void print(String stringParam){
        try {
            synchronized (stringParam) {
                while (true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.demo1;

public class ThreadA extends Thread {
    private MyObject myObject;

    public ThreadA(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        myObject.print("str");
    }
}
package com.demo1;

public class ThreadB extends Thread {
    private MyObject myObject;

    public ThreadB(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        myObject.print("str");
    }
}
package com.demo1;

public class Run2 {
    public static void main(String[] args) {
        MyObject myObject = new MyObject();
        ThreadA threadA = new ThreadA(myObject);
        ThreadB threadB = new ThreadB(myObject);
        threadA.setName("a");
        threadB.setName("b");
        threadA.start();
        threadB.start();
    }
}

輸出結果:

a
a
a
a
a
a

因為ThreadA ThreadB持有相同的鎖,導致執行緒B不能執行。這也就是String 常量池所帶來的同步程式碼塊的問題。一般不使用String作為鎖物件。例如使用 new Object(),修改程式碼如下:

package com.demo1;

public class MyObject {
    public void print(Object obj){
        try {
            synchronized (obj) {
                while (true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.demo1;

public class ThreadA extends Thread {
    private MyObject myObject;

    public ThreadA(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        myObject.print(new Object());
    }
}
package com.demo1;

public class ThreadB extends Thread {
    private MyObject myObject;

    public ThreadB(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        myObject.print(new Object());
    }
}
package com.demo1;

public class Run2 {
    public static void main(String[] args) {
        MyObject myObject = new MyObject();
        ThreadA threadA = new ThreadA(myObject);
        ThreadB threadB = new ThreadB(myObject);
        threadA.setName("a");
        threadB.setName("b");
        threadA.start();
        threadB.start();
    }
}

輸出結果:

a
b
a
b
a
b
a
b
a
b

很明顯 a,b交替得到cpu資源。