Я написал ниже программу, в которой поток even
будет печатать четные числа, тогда как поток odd
печатает нечетные числа. В дополнение к нечетным и четным потокам я создал поток control
, который определяет, является ли число четным или нечетным, и соответствующим образом устанавливает флаг. В зависимости от флага, который устанавливает поток управления, поток odd
или even
получит возможность печати.
Я использую массив в качестве источника. Управляющий поток увеличивает index
, поэтому нечетный или четный поток может получить число из массива и распечатать.
Ниже приведен полный код с комментариями.
package com.example.practice;
public class OddEvenDemoVer2 {
// Since all of these variable are used in a synchronized block, I think we
// don't need them to be as volatile, as synchronized enforces
// memory-barrier and hence all thread would see latest values.
static boolean printEven = false;
static boolean printingDone = false;
static int index = 0;
static volatile boolean stop = false;
static volatile boolean oddThreadStarted = false;
static volatile boolean evenThreadStarted = false;
public static void main(String[] args) throws InterruptedException {
Object _controlLock = new Object();
Object _indexControlLock = new Object();
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
class ControlThread implements Runnable {
@Override
public void run() {
// Wait for proper initialization of odd and even threads.
while (!oddThreadStarted && !evenThreadStarted) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (; !stop;) {
// This is to make sure that we give chance to OddThread or
// EvenThread to print the values.
// Here, we are only setting the flag which thread should
// print the number, the advancing of index is done in
// another block.
synchronized (_controlLock) {
if (arr[index] % 2 == 0) {
printEven = true;
}
else {
printEven = false;
}
_controlLock.notifyAll();
}
// This is to make sure we advance index only when printing
// has been done either by OddThread or EvenThread
synchronized (_indexControlLock) {
while (printingDone != true) {
try {
_indexControlLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
index++;
if (index > 9) {
stop = true;
}
}
}
}
}
class EvenPrintingThread implements Runnable {
@Override
public void run() {
evenThreadStarted = true;
// Loop until stop is signaled by ControlThread
for (; !stop;) {
synchronized (_controlLock) {
while (printEven != true) {
try {
_controlLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Even printing thread --> " + arr[index]);
// This is to signal control thread that printing has
// been done and now index can be advanced.
synchronized (_indexControlLock) {
printingDone = true;
_indexControlLock.notify();
}
}
}
}
}
class OddPrintingThread implements Runnable {
@Override
public void run() {
oddThreadStarted = true;
// Loop until stop is signaled by ControlThread
for (; !stop;) {
synchronized (_controlLock) {
while (printEven != false) {
try {
_controlLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Odd printing thread --> " + arr[index]);
// This is to signal control thread that printing has
// been done and now index can be advanced.
synchronized (_indexControlLock) {
printingDone = true;
_indexControlLock.notify();
}
}
}
}
}
Thread controlThread = new Thread(new ControlThread());
controlThread.start();
Thread evenThread = new Thread(new EvenPrintingThread());
Thread oddThread = new Thread(new OddPrintingThread());
evenThread.start();
oddThread.start();
Thread.sleep(1000000L);
}
}
I Ожидается, что эта программа будет работать, однако она работает нестабильно. Например, один из выходных данных:
Odd printing thread --> 1
Odd printing thread --> 1
Odd printing thread --> 1
Odd printing thread --> 1
...
Odd printing thread --> 1
Odd printing thread --> 1
Odd printing thread --> 1
Odd printing thread --> 10
Odd printing thread --> 10
Odd printing thread --> 10
Odd printing thread --> 10
Я видел в Интернете некоторые другие способы решения аналогичной проблемы, однако, когда я начал с этого (не ища готового решения в Интернете), вышеупомянутый подход пришел мне на ум. Я не хочу бросать просто потому, что это не работает. Я отлаживал, но не понял, что может быть неправильным в этом подходе.
Что мне не хватает?
РЕДАКТИРОВАТЬ
Прикрепление снимка экрана, на котором показаны два потока, «владеющих» одним и тем же идентификатором объекта.