简体   繁体   English

java线程替代同步

[英]java threads alternative to synchronization

I am new to concurrent programming and I am facing few issues with the below code using Java threads.我是并发编程的新手,我在使用 Java 线程的以下代码中遇到了一些问题。

Status Class (this class tracks the position availability):状态类(此类跟踪位置可用性):

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 Class: 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 Class:线程测试类:

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();
}
}

Even though I have used 'synchronized' I could notice that some times Thread3 is picking up prior to Thread2 and could you please help me to resolve this issue and to acheive the following results ?即使我使用了“同步”,我也可以注意到有时 Thread3 会在 Thread2 之前启动,您能帮我解决这个问题并获得以下结果吗?

(1) Always customerThread1 should take the positions first and then followed by customerThread2 and then customerThread3 (etc...) (1) 总是 customerThread1 应该先占位,然后是 customerThread2,然后是 customerThread3(等等......)

(2) As soon as the A's position is freed by customerThread1, the position should be immediately picked up by customerThread2 (rather than customerThread2 and customerThread3 waiting till all positions are done by customerThread1).And as soon as customerThread2 finishes position 'A', then customerThread3 should pick it up, etc.. (2) 一旦customerThread1释放了A的位置,customerThread2就应该立即拾取该位置(而不是customerThread2和customerThread3等待customerThread1完成所有位置)。并且一旦customerThread2完成位置'A',那么 customerThread3 应该把它捡起来,等等。

(3) As soon as the position (A, B, etc..) is freed/available, the next customerThread should pick it up immediately. (3) 一旦位置(A、B 等)被释放/可用,下一个 customerThread 应该立即拿起它。

(4) The solution should avoid all race conditions (4) 解决方案应避免所有竞争条件

There are several fundamental problems.有几个基本问​​题。

  1. You have broken code and already noticed that it doesn't work.您已经破坏了代码并且已经注意到它不起作用。 But instead of asking how to fix that broken code, you are asking for alternatives with higher performance.但是,您不是询问如何修复损坏的代码,而是要求具有更高性能的替代方案。 You will never manage to write working programs with that attitude.您将永远无法以这种态度编写工作程序。

  2. Apparently, you have no idea, what synchronized does.显然,您不知道synchronized是做什么的。 It acquires a lock on a particular object instance which can be held by one thread only.它获取只能由一个线程持有的特定对象实例的锁。 Therefore, all code fragments synchronizing on the same object are enforced to be executed ordered, with the necessary memory visibility.因此,所有在同一对象上同步的代码片段都被强制按顺序执行,并具有必要的内存可见性。 So your code fails for two reasons:所以你的代码失败有两个原因:

    1. You are creating multiple instances of Status accessing the same objects referenced by a static variable.您正在创建多个Status实例,访问static变量引用的相同对象。 Since all threads use different locks, this access is entirely unsafe.由于所有线程使用不同的锁,这种访问是完全不安全的。
    2. Your occupyOrClear is declared synchronized , but your method isClear is not.你的occupyOrClear被声明为synchronized ,但你的方法isClear不是。 So even if all threads were using the same lock instance for occupyOrClear , the result of isClear remained unpredictable due to its unsafe access to the map.因此,即使所有的线程使用了相同的锁实例occupyOrClear ,结果isClear因为它不安全的访问地图仍然是不可预知的。
  3. You have code of the form你有表格的代码
    if(status.isClear(position)) { status.occupyOrClear(position, false); …
    which matches the check-then-act anti-pattern.check-then-act反模式相匹配。 Even if each of these two method calls were thread-safe, this sequence still remained unsafe, because between these two invocations, everything can happen, most notably, the condition, the thread just checked, may change without the thread noticing.即使这两个方法调用中的每一个都是线程安全的,这个顺序仍然是不安全的,因为这两个调用之间,一切都可能发生,最值得注意的是,线程刚刚检查的条件可能会在线程不注意的情况下发生变化。 So two or more threads could invoke isClear , receiving true and then proceed with occupyOrClear .因此,两个或更多线程可以调用isClear ,接收true ,然后继续执行occupyOrClear

  4. You are using Thread.sleep .您正在使用Thread.sleep

You can try with the following pseudocode:您可以尝试使用以下伪代码:

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
            }
       }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM