Связь между потоками в Java без блокировки
Итак, чего я хочу добиться, так это двух потоков, выполняющих свою задачу по очереди. У меня изначально был только один вопрос;
- Как я могу добиться, чтобы два потока по очереди выполняли свою задачу без использования блокировки? Причина, по которой я не хочу блокировку, заключается в том, что я чувствую себя глупо, использую блокировку, когда нет общего ресурса, к которому два потока пытаются получить доступ.
Поэтому я собирался сделать небольшой пример кода, а затем обнаружил, что не могу заставить его работать, даже с блокировками. Итак, мой второй вопрос: Как я могу заставить код работать как ожидалось? То, как я это вижу, должно работать, но это только я:)
- Thread1 печатает сообщение
- Thread1 сигнализирует, что Thread2 может напечатать сообщение
- 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();
}
}
2 ответа
(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
для простых случаев, подобных этому. На самом деле вы должны лучше понять это, прежде чем использовать более "продвинутые" вещи.
(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
Вы можете использовать поток notify() и wait (): Oracle Documentation