看一段伪代码
String a = "a";
String b = "a";
String c = new String("a");
System.out.println(a==b);//true
System.out.println(a==c);//false
因为java的String类型会有一个常量池管理String对象,当出现的String对象在String池中不存在时即在String池中创建该对象,a和b都指向了同一个地址。而new则会分配一个新的地址然后复制常量池的内容,若内容不存在,常量池创建完再复制,虽然内容一样可是c和a(b)指向的地址已经不一样了。
package com.myObject;
public class Object1 {
public void print(String str) {
try {
synchronized (str) {
while (true) {
System.out.println(System.currentTimeMillis() + " "+ Thread.currentThread().getName());
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.myThread;
import com.myObject.Object1;
public class Thread1a extends Thread {
Object1 object1;
public Thread1a(Object1 object1) {
this.object1 = object1;
}
@Override
public void run() {
super.run();
object1.print("A");
}
}
package com.myThread;
import com.myObject.Object1;
public class Thread1b extends Thread {
Object1 object1;
public Thread1b(Object1 object1) {
this.object1 = object1;
}
@Override
public void run() {
super.run();
object1.print("A");
}
}
package com.myThread;
import com.myObject.Object1;
public class Thread1c extends Thread {
Object1 object1;
String c;
public Thread1c(Object1 object1,String str) {
this.object1 = object1;
this.c=str;
}
@Override
public void run() {
super.run();
object1.print(c);
}
}
package com.myThread;
import com.myObject.Object1;
public class Thread1d extends Thread {
Object1 object1;
String d=new String ("A");
public Thread1d(Object1 object1,String str) {
this.object1 = object1;
this.d = str;
}
@Override
public void run() {
super.run();
object1.print(d);
}
}
package com.test;
import com.myObject.Object1;
import com.myThread.Thread1a;
import com.myThread.Thread1b;
import com.myThread.Thread1c;
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Object1 object1 = new Object1();
String str = new String ("A");
Thread1a thread1a = new Thread1a(object1);
thread1a.setName("a");
thread1a.start();
Thread1b thread1b = new Thread1b(object1);
thread1b.setName("b");
thread1b.start();
Thread1c thread1c = new Thread1c(object1,str);
thread1c.setName("c");
thread1c.start();
Thread1d thread1d = new Thread1d(object1,str);
thread1d.setName("d");
thread1d.start();
}
}
操作 | run | 结果 | 分析 |
---|---|---|---|
注释ThreadC和D | A:object1.print(“A”); B:object1.print(“A”); | 同步,B被阻塞 | “A”,在Java中的内存地址一样 |
注释ThreadC和D | A:object1.print(“A”); B:object1.print(“B”); | 异步 | |
注释ThreadB和D | A:object1.print(“A”); C:object1.print(c); | 异步 | “A”和new(“A”)在Java中的内存地址不一样 |
注释ThreadA和B | C:object1.print(c); D:object1.print(d); | 同步 | c和d都是指向new(“A”)在Java中的内存地址一样,同一个对象 |
ThreadC和D的c和d分别由自己new | C:object1.print(c); D:object1.print(d); | 异步 | c和d指向的new(“A”)在Java中的内存地址不一样 |
总结
一般情况下,synchronized同步代码块是不会用String作为锁对象,因为String池的存在,直接使用(“a”“b”等非new的String对象)很容易造成多个线程抢夺同一个String资源,可以改用Object对象,因为通常都不会用new String()