gpt4 book ai didi

Java 多线程执行受阻

转载 作者:行者123 更新时间:2023-12-01 04:53:07 24 4
gpt4 key购买 nike

出于学习目的,我尝试实现一个线程安全的队列数据结构+消费者/生产者链,出于学习目的,我也没有使用通知/等待机制:

同步队列:

package syncpc;

/**
* Created by Administrator on 01/07/2009.
*/
public class SyncQueue {

private int val = 0;
private boolean set = false;


boolean isSet() {
return set;
}

synchronized public void enqueue(int val) {
this.val = val;
set = true;
}

synchronized public int dequeue() {
set = false;
return val;
}
}

消费者:

package syncpc;

/**
* Created by Administrator on 01/07/2009.
*/
public class Consumer implements Runnable {
SyncQueue queue;

public Consumer(SyncQueue queue, String name) {
this.queue = queue;

new Thread(this, name).start();
}


public void run() {

while(true) {
if(queue.isSet()) {
System.out.println(queue.dequeue());
}

}
}
}

制作人:

package syncpc;

import java.util.Random;

/**
* Created by Administrator on 01/07/2009.
*/
public class Producer implements Runnable {
SyncQueue queue;

public Producer(SyncQueue queue, String name) {

this.queue = queue;
new Thread(this, name).start();
}

public void run() {
Random r = new Random();

while(true) {
if(!queue.isSet()) {
queue.enqueue(r.nextInt() % 100);
}
}
}
}

主要内容:

import syncpcwn.*;

/**
* Created by Administrator on 27/07/2015.
*/
public class Program {

public static void main(String[] args) {
SyncQueue queue = new SyncQueue();

new Producer(queue, "PROCUDER");
new Consumer(queue, "CONSUMER");
}


}

这里的问题是,如果 isSet 方法不同步,我会得到这样的输出:

97,
55

程序继续运行,不输出任何值。而如果 isSet 方法同步,则​​程序正常工作。

我不明白为什么,没有死锁,isSet 方法只是查询 set 实例变量而不设置它,所以不存在竞争条件。isSet p>

最佳答案

set 需要volatile:

private boolean volatile set = false;

这确保所有读者在写入完成时看到更新的值。否则他们最终会看到缓存的值。这在 this 中有更详细的讨论。有关并发性的文章,还提供了使用 volatile 的不同模式的示例。

现在您的代码使用 synchronized 的原因可能最好用一个例子来解释。 synchronized 方法可以写成如下(即,它们等效于以下表示):

public class SyncQueue {

private int val = 0;
private boolean set = false;


boolean isSet() {
synchronized(this) {
return set;
}
}

public void enqueue(int val) {
synchronized(this) {
this.val = val;
set = true;
}
}

public int dequeue() {
synchronized(this) {
set = false;
return val;
}
}
}

在这里,实例本身用作锁。这意味着只有线程可以持有该锁。这意味着任何线程都将总是获得更新的值,因为只有一个线程可以写入该值,而一个线程想要读取set 将无法执行 isSet 直到另一个线程释放 this 上的锁,此时point set 的值将被更新。

如果你想正确理解 Java 中的并发,你真的应该阅读 Java: Concurrency In Practice (我认为某处也有免费的 PDF)。我仍在阅读这本书,因为还有很多我不理解或错误的地方。


作为matt forsythe评论,当你有多个消费者时,你会遇到问题。这是因为它们都可以检查 isSet() 并发现有一个值要出列,这意味着它们都将尝试使同一个值出列。归结为这样一个事实,即您真正想要的是“如果设置则检查并出列”操作是有效的原子操作,但它不是您编写代码的方式。这是因为最初调用 isSet 的同一线程可能不一定是随后调用 dequeue 的同一线程。所以操作作为一个整体不是原子的,这意味着您必须同步整个操作。

关于Java 多线程执行受阻,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31708903/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com