尽量不要使用 synchronized(String a) 因为 JVM 中,字符串常量池具有缓存功能!
例子1
package ThreadTest;
//String常量做synchronized锁的问题
public class synchronizedDemo01 {
//这两个字符串变量r1和r2实际上指向的是字符串常量池中的同一个数据
private static String r1 = "a";
private static String r2 = "a";
public static void main(String[] args) {
//定义线程1
new Thread(()->{
synchronized (r1){
System.out.println("获取资源1");
while (true){
try {
System.out.println(Thread.currentThread().getName()+"执行中");
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
},"线程1").start();
//定义线程2
new Thread(()->{
synchronized (r2){
System.out.println("获取资源2");
}
},"线程2").start();
}
}
结果:
获取资源1
线程1执行中
线程1执行中
线程1执行中
线程1执行中
线程1执行中
线程1执行中
...
例子2
package ThreadTest;
//String常量做synchronized锁的问题
public class synchronizedDemo02 {
//这两个字符串变量r1和r2实际上指向的是字符串常量池中的同一个数据
private static String r1 = "a";
private static String r2 = "b";
public static void main(String[] args) {
//定义线程1
new Thread(()->{
synchronized (r1){
System.out.println("获取资源1");
while (true){
try {
System.out.println(Thread.currentThread().getName()+"执行中");
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
},"线程1").start();
//定义线程2
new Thread(()->{
synchronized (r2){
System.out.println("获取资源2");
}
while (true){
try {
System.out.println(Thread.currentThread().getName()+"执行中");
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"线程2").start();
}
}
结果:
获取资源1
获取资源2
线程1执行中
线程2执行中
线程2执行中
线程1执行中
线程2执行中
线程1执行中
...
总结: 尽量不要使用 synchronized(String a) 因为 JVM 中,字符串常量池具有缓存功能; 如果非要用,则需要注意做好对象区分