【发布时间】:2020-07-11 12:39:42
【问题描述】:
我正在使用以下代码。我无法实现同步。按照我的说法,字符串池的概念应该在这里起作用。
我想知道问题背后的原因,而不是替代方案。
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SynchronizationBug {
private static Map<String,Date> concurrentMap=new ConcurrentHashMap();
public static void start(String processId) throws InterruptedException{
final String lock="log"+processId;
synchronized (lock) {
if(concurrentMap.containsKey(processId)) {
System.out.println("Process is already working and started at "+concurrentMap.get(processId));
return;
}
concurrentMap.put(processId,new Date());
}
}
public static void main(String[] args) throws InterruptedException {
// System.out.println(isPrime(10));
final String pId="p1";
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
start(pId);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
start(pId);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
for (String s:concurrentMap.keySet()) {
System.out.println(s+" - "+concurrentMap.get(s));
}
}
}
如果我锁定了作为方法参数传递的 processId,那么一切都会按预期工作。 Java的这种行为的原因是什么。我已经在 Java8 Eclipse IDE 上测试过了。
编辑: 如果字符串池概念没有相关性,那么以下代码如何正常工作。
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SynchronizationBug {
private static Map<String,Date> concurrentMap=new ConcurrentHashMap();
public static void start(String processId) throws InterruptedException{
final String lock="log"+processId;
synchronized (processId) {
if(concurrentMap.containsKey(processId)) {
System.out.println("Process is already working and started at "+concurrentMap.get(processId));
return;
}
concurrentMap.put(processId,new Date());
}
}
public static void main(String[] args) throws InterruptedException {
// System.out.println(isPrime(10));
final String pId1="p1";
final String pId2="p1";
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
start(pId1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
start(pId2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
for (String s:concurrentMap.keySet()) {
System.out.println(s+" - "+concurrentMap.get(s));
}
}
}
在这里,我传递了两个具有相同值的不同字符串对象。由于它们在池中的相同引用,锁定工作正常。 请纠正我....
【问题讨论】:
-
您在哪里看到字符串池概念?事实上,每次调用
start方法时,您显然是在不同的对象上进行同步。 -
“按照我的说法,字符串池的概念应该在这里起作用。” 你为什么这么认为?因为它没有。
-
“编辑”代码起作用的原因是您锁定了
processId,而不是lock。这不是因为您传递了两个不同的字符串对象,因为 - 这实际上是因为字符串池 -pId1和pId2具有相同的值;这就是你要锁定的价值。
标签: java multithreading synchronization string-pool