對String在多執行緒中的一些簡單認識
最近在看多執行緒,synchronized程式碼塊時候說到用String物件來當作鎖,然後說最好不要用String物件來當作鎖,這是為什麼了?可以先看一段程式。
public class StringLock {
public void method() {
//new String("字串常量")
synchronized ("字串常量") {
try {
while(true){
System.out.println("當前執行緒 : " + Thread.currentThread().getName() + "開始" );
Thread.sleep(1000);
System.out.println("當前執行緒 : " + Thread.currentThread().getName() + "結束");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main (String[] args) {
final StringLock stringLock = new StringLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
},"t2");
t1.start();
t2.start();
}
}
程式執行的結果(部分)是:
當前執行緒 : t1開始
當前執行緒 : t1結束
不斷輸出這兩句話,這是為什麼了?因為鎖"字串常量"
是一個常量鎖,當你將鎖"字串常量"
改成new String("字串常量")
,控制檯會輸出什麼了,t2執行緒也可以開始運行了。程式執行的結果(部分)是:
當前執行緒 : t1開始
當前執行緒 : t2開始
當前執行緒 : t2結束
當前執行緒 : t1結束
這是因為new String("字串常量")
建立的是不同的物件,所以鎖不同,兩個執行緒都能執行。這讓我想起了我們剛學java的時候有一些書本上會講到這個列子:
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = "hello";
System.out.println(s1 == s2);// false
System.out.println(s1.equals(s2));// true
}
new String("hello")
和"hello"
是兩個不同的物件,一個是儲存在常量池中,一個是儲存在堆中。有些時候業務上就是需要傳入一個new String的物件鎖了,可以將鎖改成new String("字串常量").intern()
,這個鎖的本質其實和"字串常量"
這個鎖是一樣的。
看看jdk的文件說的:一個初始為空的字串池,它由類 String 私有地維護。 當呼叫 intern 方法時,如果池已經包含一個等於此 String 物件的字串(用 equals(Object) 方法確定),則返回池中的字串。否則,將此 String 物件新增到池中,並返回此 String 物件的引用。
對於String物件鎖在業務上的例子可以參考這篇博文https://www.cnblogs.com/xrq730/p/6662232.html