我是并发编程的新手,我在使用Java线程时遇到以下代码的问题。
状态类(此类跟踪位置可用性):
public class Status {
private static Map<String, Boolean> positions = new HashMap<>();
static {
//Initially all positions are free (so set to true)
positions.put("A", true);
positions.put("B", true);
}
public synchronized void occupyOrClear(String position,
boolean status) {
positions.put(position, status);
}
public boolean isClear(String position) {
return positions.get(position);
}
}
MyThread类:
public class MyThread implements Runnable {
private String[] positions;
private String customer;
public MyThread(String customer, String[] positions) {
this.positions = positions;
this.customer = customer;
}
private Status status = new Status();
public void run() {
for (int i = 0; i < positions.length;) {
String position = positions[i];
if (status.isClear(position)) {
// position occupied now
status.occupyOrClear(position, false);
System.out.println(position + " occupied by :"+customer);
try {
//my real application logic goes below (instead of sleep)
Thread.sleep(2000);
} catch (InterruptedException inteExe) {
System.out.println(" Thread interrupted ");
}
// Now clear the position
status.occupyOrClear(position, true);
System.out.println(position + " finished & cleared by:"+customer);
i++;
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException inteExe) {
System.out.println(" Thread interrupted ");
}
}
}
}
}
ThreadTest类:
public class ThreadTest {
public static void main(String[] args) {
String[] positions = { "A", "B"};
Status status = new Status();
Thread customerThread1 = new Thread(new MyThread(status, "customer1", positions));
Thread customerThread2 = new Thread(new MyThread(status, "customer2", positions));
Thread customerThread3 = new Thread(new MyThread(status, "customer3", positions));
customerThread1.start();
customerThread2.start();
customerThread3.start();
}
}
即使我已经使用了&#39; synchronized&#39;我注意到有些时候Thread3在Thread2之前就已经开始了,你能否帮我解决这个问题并获得以下结果?
(1)总是customerThread1应该首先占据位置然后 然后是customerThread2,然后是customerThread3(etc ...)
(2)一旦A&#39的位置被customerThread1释放,那么 应立即通过customerThread2(而不是 比customerThread2和customerThread3等到所有位置 由customerThread1完成。并在customerThread2完成后立即完成 位置&#39; A&#39;然后customerThread3应该拿起它等等。
(3)一旦位置(A,B等)被释放/可用,下一个 customerThread应该立即拿起它。
(4)解决方案应避免所有竞争条件
答案 0 :(得分:1)
有几个基本问题。
您破坏了代码并且已经注意到它无效。但是,不是要求如何修复破碎的代码,而是要求具有更高性能的替代方案。你永远不会以这种态度编写工作程序。
显然,你不知道synchronized
做了什么。它获取对特定对象实例的锁定,该锁定只能由一个线程持有。因此,在同一对象上同步的所有代码片段都被强制执行,并具有必要的内存可见性。所以你的代码失败有两个原因:
Status
的多个实例,这些实例访问static
变量引用的相同对象。由于所有线程都使用不同的锁,因此这种访问完全不安全。occupyOrClear
已宣布为synchronized
,但您的方法isClear
未被宣布为occupyOrClear
。因此,即使所有线程都使用isClear
的相同锁实例,if(status.isClear(position)) { status.occupyOrClear(position, false); …
的结果仍然是不可预测的,因为它不安全地访问地图。您的代码形式为
isClear
它匹配 check-then-act 反模式。即使这两个方法调用中的每一个都是线程安全的,这个序列仍然是不安全的,因为在这两个调用之间,所有事情都可能发生,最值得注意的是,刚刚检查过的条件可能会发生变化而没有线程注意到。因此,两个或多个线程可以调用true
,接收occupyOrClear
,然后继续Thread.sleep
。
您正在使用On branch master
changes not staged for commit:
。
答案 1 :(得分:0)
您可以尝试使用以下伪代码:
main() {
//some concurrent queues, eg ConcurrentLinkedQueue
Queue t1Tasks = new Queue("A","B","C");
Queue t2Tasks = new Queue();
Queue t3Tasks = new Queue();
Thread t1 = new PThread(t1Tasks,t2Tasks,"customer1");
Thread t2 = new PThread(t2Tasks,t3Tasks,"customer2");
Thread t3 = new PThread(t3Tasks,null,"customer3");
}
PThread {
Queue q1,q2;
PThread(Queue q1, Queue q2,...){}
run() {
while (item = q1.get()) {
//process item
q2.put(item); //to be processed by next thread
}
}
}