Kon*_*che 28 java linux multithreading posix pthreads
这个问题不是关于,虚假的唤醒是否真的很开心,因为这已经在这里全面讨论过:虚假的唤醒真的发生了吗?因此,这也不是为什么我必须围绕我的wait声明循环.这是关于:
我想构建一个虚假唤醒发生的案例.到目前为止我在上面提到的问题中学到的是:
如果发出一个Linux进程的信号,它的等待线程将各自享受一个不错的,热的虚假唤醒.
所以看来这只能用于linux机器,实际上我有Ubuntu 11.04 - 64位.我编写了一个Java程序,其中一个线程正在等待一个条件,但没有循环和另一个类,线程只是等待并被另一个线程通知.我认为在一个JVM中启动所有三个线程会强制执行上述情况,但似乎并非如此.
有没有其他人知道如何在Java中构建这样的案例?
Boh*_*ian 17
你不能强制进行虚假唤醒,但是对于正在运行的线程,虚假唤醒与常规唤醒无法区分(事件的来源不同,但事件本身是相同的)
要模拟虚假唤醒,只需调用notify() ;
调用interrupt()不合适,因为这样做会设置中断标志,并且在虚假唤醒之后,不会设置中断标志
"虚假唤醒"是一个hotchpotch,涵盖了该领域的任何实现细节.因此,很难弄清楚"真正的"虚假唤醒是什么以及为什么另一个是"不真实的" - 更不用说这个实现细节来自哪个层.从"内核","系统库(libc)","JVM","Java标准库(rt.jar)"或构建在此堆栈之上的自定义框架中选择任何一个.
以下程序显示使用java.util.concurrent东西的虚假唤醒:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SpuriousWakeupRWLock {
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
static int itemsReady;
public static void main(String[] args) throws Exception {
// let consumer 1 enter condition wait
new ConsumerOne().start();
Thread.sleep(500);
lock.lock();
try {
// let consumer 2 hit the lock
new ConsumerTwo().start();
Thread.sleep(500);
// make condition true and signal one (!) consumer
System.out.println("Producer: fill queue");
itemsReady = 1;
condition.signal();
Thread.sleep(500);
}
finally {
// release lock
lock.unlock();
}
System.out.println("Producer: released lock");
Thread.sleep(500);
}
abstract static class AbstractConsumer extends Thread {
@Override
public void run() {
lock.lock();
try {
consume();
} catch(Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
abstract void consume() throws Exception;
}
static class ConsumerOne extends AbstractConsumer {
@Override
public void consume() throws InterruptedException {
if( itemsReady <= 0 ){ // usually this is "while"
System.out.println("One: Waiting...");
condition.await();
if( itemsReady <= 0 )
System.out.println("One: Spurious Wakeup! Condition NOT true!");
else {
System.out.println("One: Wakeup! Let's work!");
--itemsReady;
}
}
}
}
static class ConsumerTwo extends AbstractConsumer {
@Override
public void consume() {
if( itemsReady <= 0 )
System.out.println("Two: Got lock, but no work!");
else {
System.out.println("Two: Got lock and immediatly start working!");
--itemsReady;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
One: Waiting...
Producer: fill queue
Producer: released lock
Two: Got lock and immediatly start working!
One: Spurious Wakeup! Condition NOT true!
Run Code Online (Sandbox Code Playgroud)
使用过的JDK是:
java version "1.6.0_20"
OpenJDK Runtime Environment (IcedTea6 1.9.9) (6b20-1.9.9-0ubuntu1~10.04.2)
OpenJDK 64-Bit Server VM (build 19.0-b09, mixed mode)
Run Code Online (Sandbox Code Playgroud)
它基于以下一个实现细节java.util.concurrent:标准Lock有一个等待队列,Condition另一个等待队列.如果发出条件信号,则将发出信号的线程从条件的队列移动到锁的队列中.实现细节:它在队列末尾移动.如果另一个线程已经在锁定队列中等待并且第二个线程没有访问条件变量,则该线程可以"窃取"该信号.如果实现将第一个线程放在第二个线程之前,则不会发生这种情况.这个"奖励"可以/将基于第一个线程已经获得锁定一次并且与相同锁定相关联的条件中的等待时间被记入该线程的事实.
我将此定义为"虚假",因为
使用以下代码演示最后一点Object.wait():
public class SpuriousWakeupObject {
static Object lock = new Object();
static int itemsReady;
public static void main(String[] args) throws Exception {
// let consumer 1 enter condition wait
new ConsumerOne().start();
Thread.sleep(500);
// let consumer 2 hit the lock
synchronized (lock) {
new ConsumerTwo().start();
Thread.sleep(500);
// make condition true and signal one (!) consumer
System.out.println("Producer: fill queue");
itemsReady = 1;
lock.notify();
Thread.sleep(500);
} // release lock
System.out.println("Producer: released lock");
Thread.sleep(500);
}
abstract static class AbstractConsumer extends Thread {
@Override
public void run() {
try {
synchronized(lock){
consume();
}
} catch(Exception e){
e.printStackTrace();
}
}
abstract void consume() throws Exception;
}
static class ConsumerOne extends AbstractConsumer {
@Override
public void consume() throws InterruptedException {
if( itemsReady <= 0 ){ // usually this is "while"
System.out.println("One: Waiting...");
lock.wait();
if( itemsReady <= 0 )
System.out.println("One: Spurious Wakeup! Condition NOT true!");
else {
System.out.println("One: Wakeup! Let's work!");
--itemsReady;
}
}
}
}
static class ConsumerTwo extends AbstractConsumer {
@Override
public void consume() {
if( itemsReady <= 0 )
System.out.println("Two: Got lock, but no work!");
else {
System.out.println("Two: Got lock and immediatly start working!");
--itemsReady;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
One: Waiting...
Producer: fill queue
Producer: released lock
One: Wakeup! Let's work!
Two: Got lock, but no work!
Run Code Online (Sandbox Code Playgroud)
这里的实现似乎按照我的预期进行:使用条件的线程首先被唤醒.
最后的注释:这个原理的想法来自于为什么java.util.concurrent.ArrayBlockingQueue使用'while'循环而不是'if'来调用await()?虽然我的解释不同,但代码来自我自己.
| 归档时间: |
|
| 查看次数: |
3108 次 |
| 最近记录: |