java线程替代同步

时间:2016-09-27 12:52:05

标签: java multithreading concurrency concurrentmodification

我是并发编程的新手,我在使用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)解决方案应避免所有竞争条件

2 个答案:

答案 0 :(得分:1)

有几个基本问​​题。

  1. 您破坏了代码并且已经注意到它无效。但是,不是要求如何修复破碎的代码,而是要求具有更高性能的替代方案。你永远不会以这种态度编写工作程序。

  2. 显然,你不知道synchronized做了什么。它获取对特定对象实例的锁定,该锁定只能由一个线程持有。因此,在同一对象上同步的所有代码片段都被强制执行,并具有必要的内存可见性。所以你的代码失败有两个原因:

    1. 您正在创建Status的多个实例,这些实例访问static变量引用的相同对象。由于所有线程都使用不同的锁,因此这种访问完全不安全。
    2. 您的occupyOrClear已宣布为synchronized,但您的方法isClear未被宣布为occupyOrClear。因此,即使所有线程都使用isClear的相同锁实例,if(status.isClear(position)) { status.occupyOrClear(position, false); …的结果仍然是不可预测的,因为它不安全地访问地图。
  3. 您的代码形式为
    isClear
    它匹配 check-then-act 反模式。即使这两个方法调用中的每一个都是线程安全的,这个序列仍然是不安全的,因为在这两个调用之间,所有事情都可能发生,最值得注意的是,刚刚检查过的条件可能会发生变化而没有线程注意到。因此,两个或多个线程可以调用true,接收occupyOrClear,然后继续Thread.sleep

  4. 您正在使用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
            }
       }
}