- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
出于学习目的,我尝试实现一个线程安全的队列数据结构+消费者/生产者链,出于学习目的,我也没有使用通知/等待机制:
同步队列:
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/
我是一名优秀的程序员,十分优秀!