为什么这个多线程程序会陷入无限循环? [英] Why is this multithreaded program getting stuck at infinite loop?

查看:64
本文介绍了为什么这个多线程程序会陷入无限循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的程序是一个简单的线程程序.由于某种我无法想象的原因,它在两个线程中同时陷入了生产()和消费()方法的无限循环.

The below program is a simple threaded program . For some reason which i am not able to figure , its getting stuck at infinite loop of both produce() and consume() methods simultaneously in both the threads.

它产生了几次输出,然后在控制台上没有输出.所以我认为它陷入了循环.

It produces the output for a few times and then there is no output at the console. So I presume its getting stuck at the loop.

我的问题是,由于循环取决于 Item 类的同一对象的标志 valueSet 的值,valueSet 不能同时为 true 和 false同时 .因此,produce() 或 cosume() 方法的循环都应该为 false,并且输出的打印应该继续.

My question is , since the loop depends on the value of the flag valueSet of the same object of Item class , valueSet can't be both true and false at the same time . So either of the produce() or cosume() method's loop should get false and the printing of output should continue.

但这不会发生在这里.那么,如果条件依赖于一次只能取真或假的标志变量,为什么它会卡在 while 循环中呢?

But that's not happening here. So why is it getting stuck at the while loop if the condition depends on the flag variable which can only take true or false at a time ?

class Item{
    boolean valueSet = false ; 
    int item = 0 ; 

    public  void consume(){
        while(!valueSet) ;
        System.out.println("Consumed : "  + item ) ; 
        valueSet = false ;
    }

    public  void produce(int n ){
        while(valueSet);
        item = n ;
        System.out.println("Produced : "  + item ) ; 
        valueSet = true ;
    } 
}

class Producer implements Runnable{
 Item item ;
 Producer(Item itemobj){
     item = itemobj ; 
 }

 public void run(){
     while(true){
         System.out.println("\nProducing ....") ; 
     item.produce((int)Math.random()*100) ; 
     }
 }

}

class Consumer implements Runnable{
    Item item  ;
    Consumer(Item itemobj){item = itemobj ; }

    public void run(){
        while(true){
            System.out.println("\nConsuming !") ;
        item.consume() ; 

        }
    }
}


class Main{
    public static void main(String[] args) {
        Item item = new Item() ;
        Thread consumer = new Thread(new Consumer(item)) ; 
        Thread producer = new Thread(new Producer(item)) ;
        System.out.println("\nStarted producer and consumer threads : ") ; 
        consumer.start() ; 
        producer.start() ; 
    }
}

更新:

while(valueSet) 在一个线程中陷入无限循环时,不应该 while(!valuSet) 跳出循环并翻转 值集?这会反过来导致 while(valueSet) 跳出循环,对吗?

When the while(valueSet) is stuck at infinite loop in one thread , shouldn't while(!valuSet) get out of loop and flip the valueSet? This would inturn cause while(valueSet) to come out of loop right ?

根据某些答案,当 while(valueSet) 卡住时,另一个线程似乎无法访问 valueSet .我不明白这是怎么发生的.请解释您的答案.

As per some answers it seems when while(valueSet) is stuck , the other thread is somehow not able to access valueSet . I don't understand how this is happening. Please explain your answer.

我看到将 volatile 用于 valueSet 将修复它,但我无法理解如何不使用它.即使它依赖于一个不能同时为真和假的标志 valueSet,它也会导致无限循环.

I see that using volatile for valueSet will fix it but i am not able to understand how without using it. It's causing the infinite loop even if it depends on one flag valueSet which can't be true and false at the same time.

推荐答案

基本上,您在这里尝试做的是使用 valueSet 作为布尔标志来同步 ConsumerProducer -- 让它们依次工作.valueSet 确实只能在某一时刻为真或假;然而,这不是两个线程(消费者和生产者)如何看待它.

Basically, what you're trying to do here is to use valueSet as a boolean flag to synchronize the Consumer and Producer -- to make them work in turn. It is true that valueSet can only be true or false at one moment; however, it's not how the two threads (Consumer and Producer) view it.

我们知道在Java中,对象存储在中;这被称为主存储器.但是,对于每个线程,出于性能考虑,对使用对象的引用保存在线程特定的缓存中.在这里,ProducerConsumer 共享一个存储在堆上的Item 对象;字段 item.valueSet 可能会被每个线程缓存.

We know that in Java, objects are stored on the heap; that is called the main memory. For each thread, however, for performance's sake, references to used objects are kept in a thread-specific cache. As in here, Producer and Consumer share one Item object which is stored on the heap; the field item.valueSet might be cached by each thread.

 _______________    ______________  
 |   Consumer    |  |   Producer   |  
 |   _________   |  |   _________  |  
 |  |         |  |  |  |         | |  
 |  | Cache1  |  |  |  |  Cache2 | |  
 |  | valueSet|  |  |  | valueSet| |
 |  |_________|  |  |  |_________| |  
 |_______________|  |______________|
           | |              | |
           | |              | |
          _|_|______________|_|__
         |                       |
         |      MAIN MEMORY      | 
         |      valueSet         | 
         |_______________________|

例如,当 ConsumervalueSet 更改为 false 时,它可能会也可能不会将新值刷新到主内存;类似地,当 Producer 检查 valueSet 时,它可能会也可能不会尝试从主内存中读取最新值.这就是 volatile 关键字发挥作用的地方.当您将 valueSet 设置为 volatile 时,它确保两个线程都将最新的值写入/读取到主内存.

When, say, Consumer changes valueSet to false, it might or might not flush the new value to the main memory; similarly, when Producer checks valueSet, it might or might not try to read the newest value from the main memory. That's where the volatile keyword comes into play. When you set valueSet to be volatile, it ensures that both threads write/read the newest value to/from main memory.

请注意,上面的总结基本上被称为 JVM 内存模型.它是一组规则,用于定义多线程情况下 JVM 的行为.

Notice that the above summary is bascially known as the JVM Memory Model. It's a set of rules to define JVM's behaviour under multithreading situations.

如果您尝试更改代码的以下部分:

If you try changing the following parts of your code:

    **volatile** boolean valueSet = false ; 
    **volatile** int item = 0 ;
    ...
    item.produce((int)(Math.random()*100)) ; // added parenthesis

您将看到以下输出:

Started producer and consumer threads : 

Consuming !

Producing ....
Produced : 83

Producing ....
Consumed : 83

Consuming !
Produced : 54

Producing ....
Consumed : 54

Consuming !
Produced : 9

Producing ....
Consumed : 9

Consuming !
Produced : 23

Producing ....
Consumed : 23

这篇关于为什么这个多线程程序会陷入无限循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆