【问题标题】:Questions about Java Producer Consumer Solution关于Java生产者消费者解决方案的问题
【发布时间】:2014-12-01 06:11:04
【问题描述】:

我目前正在从一本书中阅读有关 Java Consumer-Producer 解决方案的实现。

public class Producer extends Thread {
    private IntBuffer buffer;

    public Producer( IntBuffer buffer ){
        this.buffer = buffer;
    }

    public void run(){
        Random r = new Random();
        while( true ){
        int num = r.nextInt();
        buffer.add( num );
        System.out.println( “Produced “ + num );
        }
    }
}

public class Consumer extends Thread {
    private IntBuffer buffer;

    public Consumer( IntBuffer buffer ){
        this.buffer = buffer;
    }

    public void run(){
        while( true ){
            int num = buffer.remove();
            System.out.println( “Consumed “ + num );
        }
    }
}

public class IntBuffer {
    private int index;
    private int[] buffer = new int[8];

    public void add( int num ){
        while( true ){
            if( index < buffer.length ){
                buffer[index++] = num;
                return;
            }
        }
    }

    public int remove(){
        while( true ){
            if( index > 0 ){
                return buffer[--index];
            }
        }
    }
}

IntBuffer b = new IntBuffer();
Producer p = new Producer( b );
Consumer c = new Consumer( b );
p.start();
c.start();

我有几个问题:

  1. 根据本书,此方法使用忙等待。这发生在哪里?据我所知,当一个线程正在等待另一个线程完成其执行才能恢复自己的执行时,就会发生忙碌等待。通过使用 wait() 方法,从技术上讲,线程是否仍然等待到 notify() 调用?

  2. 为什么同步添加/删除方法不能解决访问控制问题?我认为同步一词会阻止多个线程访问同一代码段。

  3. 为什么 add/remove 方法中都有一个 while(true) 循环?

【问题讨论】:

  • 您的3 回答您的1
  • @SotiriosDelimanolis - while( true ) 不只是等待吗?我的意思是他不是在等待任何条件成真..
  • @TheLostMind if 中的条件while。注意每个return
  • 它只是在等待,是的,但也阻止方法返回,直到 if() 语句中的条件变为真,此时 then 子句从 while 循环和方法中返回。
  • @SotiriosDelimanolis - 啊。我没有正确看到if 条件。谢谢:)

标签: java multithreading concurrency thread-safety


【解决方案1】:
  1. 基本上,while(true) 的作用是确保一旦缓冲区已满,每个方法都会阻塞,直到调用另一个方法。换句话说,在消费者消费完一个之前,生产者将无法生产另一个。

它通过不断检查索引值的变化来做到这一点。例如,在 add() 方法中,只要 index 不小于 buffer.length,该方法就永远不会返回。相反,它会不断检查直到索引小于 buffer.length,这只会在 remove() 被调用时发生。

  1. 那么,这是一个忙碌的等待。这意味着,您实际上并没有使用等待和通知机制来停放线程,而是使用轮询机制。你会注意到这里没有提到 wait() 和 notify() 方法——它只是通过使用 while(true) 阻塞线程。这与轮询端口和打开套接字并从服务器异步接收更新之间的区别没有什么不同。

  2. 因为这些线程故意相互阻塞,所以您无法真正摆脱同步 add() 和 remove() 方法 - 它只会导致死锁。

【讨论】:

  • 谢谢。现在我了解了代码的繁忙等待问题。但是,在同步 add 和 remove 方法方面,是什么导致了死锁?即使使用 while(true) 循环,add 方法的块是否仍然允许 remove 方法修改 bug?或者缓冲区数组本身是否被阻止访问 add/remove 方法在 while(true) 循环中?最后,我想 wait() 实际上会释放资源,而不是用 while(true) 循环不断地占用它。
  • 如果同步 add() 和 remove() 方法,它们用作锁的共享对象是 'this'(IntBuffer 的特定实例)。因此,同步可防止在任何线程仍在此类上执行任何同步方法时调用此实例的任何方法。由于对 add() 的调用在另一个线程调用 remove() 之前一直阻塞,并且 synchronized 会阻止另一个线程进入 remove() 方法,所以 add() 将永远阻塞。
猜你喜欢
  • 2016-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多