Java 中的线程间无锁通信
Communication between threads in Java without lock
所以我想要实现的是两个线程轮流执行它们的任务。我最初只有一个问题;
- 如何在不使用锁的情况下实现两个线程轮流执行任务?我不想要锁的原因是因为我觉得自己很愚蠢,在两个线程试图访问的公共资源不存在时使用锁。
所以我打算做一个代码的小例子,然后我发现我无法让它工作,即使有锁。所以我的第二个问题是;我如何使代码按预期工作?在我看来,它应该可以工作,但那只是我:)
- Thread1 打印消息
- 线程 1 表示线程 2 可以打印消息
- Thread2 打印消息
- Thread2 表示 Thread1 可以重新开始
public class App {
Lock lock = new ReentrantLock();
Condition cond1 = lock.newCondition();
Condition cond2 = lock.newCondition();
public App() {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
lock.lock();
System.out.println("Thread 1");
cond2.signalAll();
cond1.await();
lock.unlock();
}
} catch (InterruptedException e) {
}
}
});
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
lock.lock();
cond2.await();
System.out.println(" Thread 2");
cond1.signalAll();
lock.unlock();
}
} catch (InterruptedException e) {
}
}
});
thread2.start();
}
public static void main(String[] args) {
new App();
}
}
您可以使用线程 notify() 和 wait():Oracle Documentation
(1) await()
一般在循环中使用;不这样做是错误的迹象。
while( some condition not met )
cond.await();
(2) unlock()
应该在 finally
块中
(3) signal()
仅向当前等待的线程发送信号;如果没有线程在等待,信号就会丢失。
lock.lock();
cond.signal(); // lost
cond.await(); // won't wake up
(4) 对于像这样的简单情况,使用旧的 synchronized
没有错。实际上,在使用更多 "advanced" 东西之前,您最好先了解它。
(5) 一个解决方案:
Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();
int turn=1; // 1 or 2
// thread1
lock.lock();
try
{
while (true)
{
while(turn!=1)
cond.await();
System.out.println("Thread 1");
turn=2;
cond.signal();
}
}
finally
{
lock.unlock();
}
// thread2
// switch `1` and `2`
(6) 一圈线程,每个线程唤醒下一个
int N = 9;
Thread[] ring = new Thread[N];
for(int i=0; i<N; i++)
{
final int ii = i+1;
ring[i] = new Thread(()->
{
while(true)
{
LockSupport.park(); // suspend this thread
System.out.printf("%"+ii+"d%n", ii);
LockSupport.unpark(ring[ii%N]); // wake up next thread
// bug: spurious wakeup not handled
}
});
}
for(Thread thread : ring)
thread.start();
LockSupport.unpark(ring[0]); // wake up 1st thread
所以我想要实现的是两个线程轮流执行它们的任务。我最初只有一个问题;
- 如何在不使用锁的情况下实现两个线程轮流执行任务?我不想要锁的原因是因为我觉得自己很愚蠢,在两个线程试图访问的公共资源不存在时使用锁。
所以我打算做一个代码的小例子,然后我发现我无法让它工作,即使有锁。所以我的第二个问题是;我如何使代码按预期工作?在我看来,它应该可以工作,但那只是我:)
- Thread1 打印消息
- 线程 1 表示线程 2 可以打印消息
- Thread2 打印消息
- Thread2 表示 Thread1 可以重新开始
public class App {
Lock lock = new ReentrantLock();
Condition cond1 = lock.newCondition();
Condition cond2 = lock.newCondition();
public App() {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
lock.lock();
System.out.println("Thread 1");
cond2.signalAll();
cond1.await();
lock.unlock();
}
} catch (InterruptedException e) {
}
}
});
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
lock.lock();
cond2.await();
System.out.println(" Thread 2");
cond1.signalAll();
lock.unlock();
}
} catch (InterruptedException e) {
}
}
});
thread2.start();
}
public static void main(String[] args) {
new App();
}
}
您可以使用线程 notify() 和 wait():Oracle Documentation
(1) await()
一般在循环中使用;不这样做是错误的迹象。
while( some condition not met )
cond.await();
(2) unlock()
应该在 finally
块中
(3) signal()
仅向当前等待的线程发送信号;如果没有线程在等待,信号就会丢失。
lock.lock();
cond.signal(); // lost
cond.await(); // won't wake up
(4) 对于像这样的简单情况,使用旧的 synchronized
没有错。实际上,在使用更多 "advanced" 东西之前,您最好先了解它。
(5) 一个解决方案:
Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();
int turn=1; // 1 or 2
// thread1
lock.lock();
try
{
while (true)
{
while(turn!=1)
cond.await();
System.out.println("Thread 1");
turn=2;
cond.signal();
}
}
finally
{
lock.unlock();
}
// thread2
// switch `1` and `2`
(6) 一圈线程,每个线程唤醒下一个
int N = 9;
Thread[] ring = new Thread[N];
for(int i=0; i<N; i++)
{
final int ii = i+1;
ring[i] = new Thread(()->
{
while(true)
{
LockSupport.park(); // suspend this thread
System.out.printf("%"+ii+"d%n", ii);
LockSupport.unpark(ring[ii%N]); // wake up next thread
// bug: spurious wakeup not handled
}
});
}
for(Thread thread : ring)
thread.start();
LockSupport.unpark(ring[0]); // wake up 1st thread