java - 这是在 Java 中错误使用内部条件队列吗?

标签 java multithreading

此程序尝试按顺序打印数字 1 到 10,第一个线程打印奇数,第二个线程打印偶数。

我一直在阅读 JCIP 的书,它说:

Ensure that the state variables making up the condition predicate are guarded by the lock associated with the condition queue.

在下面的程序中,条件队列将对应静态成员'obj1',而组成条件谓词的状态变量是静态volatile成员'count'。 (如果我对条件、状态变量、条件谓词的解释有误,请告诉我)

下面的程序可以正常工作,但显然违反了上面的习惯用法。我是否正确理解了作者的意思?下面的代码真的是一个糟糕的编程实践吗(恰好可以正常工作)

你能举个例子吗?如果不遵循上述习语,我会遇到问题吗?

public class OddEvenSynchronized implements Runnable {
    static Object obj1 = new Object();         // monitor to share data
    static volatile int count =1;              // condition predicate
    boolean isEven; 
    public OddEvenSynchronized(boolean isEven) {   //constructor
        this.isEven=isEven;
    }
    public void run (){
        while (count<=10){
            if (this.isEven == true){
                printEven();                   //print an even number
            }
            else{
                printOdd();                     //print an odd number
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread (new  OddEvenSynchronized(true));
        Thread t2 = new Thread (new  OddEvenSynchronized(false));
        //start the 2 threads
        t1.start();       
        t2.start();
    }

    void printEven(){
        synchronized (obj1) {
            while (count%2 != 0){
                try{
                    obj1.wait();
                }catch (InterruptedException e) {
                        e.printStackTrace();
                }
            }
        }
        System.out.println("Even"+count);      

        count++;  //unguarded increment (violation)
        synchronized (obj1) {
            obj1.notifyAll();
        }
    }                            //end method
    void printOdd(){
        synchronized (obj1) {
            while (count%2 == 0){
                try{
                    obj1.wait();
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("Odd"+count);
        count++;     //unguarded increment (violation)
        synchronized (obj1) {
            obj1.notifyAll();
        }

    }                          //end method
}   //end class

最佳答案

如果您未在 obj1 上同步,请不要读取或写入 count。那是不行不行!打印和增量应该在同步块(synchronized block)内完成。

synchronized (obj1) {
    while (count%2 != 0){
        try {
            obj1.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println("Even"+count);      
}

synchronized (obj1) {
    count++;
    obj1.notifyAll();
}

您会注意到现在没有理由放弃同步。合并这两个 block 。

synchronized (obj1) {
    while (count%2 != 0){
        try {
            obj1.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    System.out.println("Even"+count);      
    count++;
    obj1.notifyAll();
}

The below program works correctly but is clearly violating the above idiom.

多线程编程的潜在危险在于,有缺陷的程序可能看起来大部分时间都能正常工作。竞争条件可能非常曲折,因为它们通常需要非常严格的时间条件,而这种情况很少发生。

严格遵守规则真的非常重要。正确地进行多线程编程非常困难。几乎可以肯定的是,只要您偏离规则并试图变得聪明,就会引入细微的错误。

关于java - 这是在 Java 中错误使用内部条件队列吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32280646/

相关文章:

java - 数据传输对象 DTO 在哪里构建

java - 无法将信息从hibernate推送到mysql数据库

java - springboot 应用程序在 Angular 上出现 fsevents 错误

c# - Monitor.TryEnter 不起作用

c - 解锁时向多个线程发出信号的一把锁

c++ - 使用epoll_wait时如何正确读取数据

java - 为什么这个线程网络代码不起作用? ( java )

java - 将 null 分配给 Java 中的 ArrayList 项

java - 无法解析符号 'App'

java - 设计——只让一个线程跨虚拟机运行