Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在java中,这是对内在条件队列的错误使用吗?_Java_Multithreading - Fatal编程技术网

在java中,这是对内在条件队列的错误使用吗?

在java中,这是对内在条件队列的错误使用吗?,java,multithreading,Java,Multithreading,此程序尝试按顺序打印数字1到10,1个线程打印奇数,第二个线程打印偶数 我一直在读JCIP的书,上面写着: 确保构成条件谓词的状态变量由与条件队列关联的锁保护 在下面的程序中,条件队列将对应于静态成员“obj1”,而构成条件谓词的状态变量是静态易失性成员“count”。(如果我对条件、状态变量、条件谓词的解释有误,请告知我) 下面的程序工作正常,但显然违反了上述习惯用法。我是否理解了作者想说的话?下面的代码真的是一个糟糕的编程实践吗(碰巧工作正常) 你能给我举个例子吗?如果不遵循上面的习惯用法,

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

我一直在读JCIP的书,上面写着:

确保构成条件谓词的状态变量由与条件队列关联的锁保护

在下面的程序中,条件队列将对应于静态成员“obj1”,而构成条件谓词的状态变量是静态易失性成员“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
public类实现可运行{
静态对象obj1=new Object();//用于共享数据的监视器
静态volatile int count=1;//条件谓词
布尔isEven;
公共OddEvenSynchronized(布尔isEven){//构造函数
this.isEven=isEven;
}
公开作废运行(){

而(count如果未在
obj1
上同步,则不要读取或写入
count
。这是不允许的!打印和增量应在同步块内完成

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

synchronized (obj1) {
    count++;
    obj1.notifyAll();
}
您会注意到现在没有理由放弃同步。请将这两个块组合起来

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

    System.out.println("Even"+count);      
    count++;
    obj1.notifyAll();
}
下面的程序工作正常,但显然违反了上述习惯用法

多线程编程的潜在危险在于,有缺陷的程序在大多数情况下似乎都能正常工作。竞争条件可能非常不稳定,因为它们通常需要非常严格的计时条件,而这种情况很少发生


严格遵守规则是非常非常重要的。要正确地进行多线程编程是非常困难的。几乎可以肯定的是,每当你偏离规则并试图变得聪明时,你都会引入一些微妙的错误。

这是我能够提出这个问题的唯一原因,正如我与John Kugelman在他的回答中(如果有问题,请更正):

1st Key insight:在Java中,只有一个条件队列与对象的监视器相关联。虽然它们共享条件队列,但条件谓词不同。这种共享会导致不必要的唤醒->检查条件谓词->再次休眠。因此,尽管效率低下,但它们仍会像f如果编码正确,则使用单独的条件队列(而(条件谓词){thread.wait()})

在上面的程序中,条件谓词

  • 计数%2==0
  • 计数%2!=0
  • 它们是不同的,尽管它们是相同条件队列的一部分(即,在此对象的监视器上执行notify()操作将唤醒它们,但一次只能有一个操作)

    第二个关键洞察: volatile count变量确保内存可见性

    结论:

    一旦我们引入另一个具有相同条件谓词的线程,程序将很容易受到竞争条件的影响(如果不是其他缺陷的话)

    另外,请注意,通常wait()notify()机制用于具有相同谓词条件的对象,例如,等待资源锁。上述程序通常用于访谈,我怀疑它在实际代码中是否常见


    因此,如果同一条件队列中有两个或多个线程具有不同的条件谓词,并且条件谓词变量是可变的(从而确保内存可见性),然后忽略上面的建议可以生成正确的程序。虽然这没有什么意义,但这确实帮助我更好地理解多线程。

    为什么它是一个“不”字?这正是我想找出的。如果仔细观察,count是不稳定的,因此不需要将其放入synchronized。我明确地将此程序设置为就是这样。对编辑的回应:在这种情况下,什么样的竞争条件会破坏程序?您的程序可能只需要两个线程就可以了。我还没有发现任何缺陷,至少现在还没有。但是如果引入更多线程,您会遇到问题。保持
    同步
    活动可确保
    计数
    不会发生错误在
    while
    循环结束和随后的打印输出后,或在打印输出之后和增量之前进行更改。严格遵守规则非常重要。不,更重要的是首先理解规则,在遵循规则之前,想象您运行了额外的“偶数”线程。通过适当的同步,这将是好的,可观察到的行为将是相同的。两个偶数线程将相互争斗,每次只有一个线程获胜,这将是好的。但是,对于您的程序,我可以想象各种竞争条件。两个线程可能同时检测并打印偶数,f或实例。这就是您要寻找的响应类型吗?如果是,我会将其添加到我的答案中。没有“内在条件队列”。只有内在锁,没有队列。这就是为什么您必须有一个条件变量和一个采集循环。您能解释一下吗?JCIP说每个对象都有一个内在锁和一个内在条件队列。您引用的引用没有这样说。它说的是“条件队列”,而不是“内在条件队列”。需要更多的上下文,但我怀疑代码本身正在实现一个条件队列。或者,这本书是错误的。如果有一个与锁相关联的条件队列,您就不需要额外的变量或采集循环。从中引用这本书,“一个物体的内在