如何确保两个线程打印奇数仍然保持这个实现的第一个奇数顺序?

我创建了两个可运行的作业:PrintEvenNumbersJob和PrintOddNumbersJob,并生成了两个线程来执行这些作业。 这似乎工作得很好! 但我闻到了这个实施的可疑之处。 我可以就此实施提出一些意见和建议吗?

我在这个实现中看到的问题是,只有当thread1获得对象锁的锁定时,程序才会终止,否则它会打印奇数的第一个偶数第二个订单并且不会终止,除非我提供另一个语句“lock.notify”之后for PrintEvenNumbersJob中的语句(如此实现中所示)。 我的问题是如何确保首先执行thread1。

public class PrintEvenNumbersJob implements Runnable { private Object lock; public PrintEvenNumbersJob(Object lock) { this.lock = lock; } @Override public void run() { synchronized (lock) { for (int i = 0; i <= 10; i += 2) { lock.notify(); System.out.println(i); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } lock.notify(); // not required if thread1 gains lock first } } } public class PrintOddNumbersJob implements Runnable { private Object lock; public PrintOddNumbersJob(Object lock) { this.lock = lock; } @Override public void run() { synchronized (lock) { for (int i = 1; i < 10; i += 2) { lock.notify(); System.out.println(i); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } lock.notify(); } } } public class EvenOddManager { public static void main(String[] args) { Object lock = new Object(); PrintEvenNumbersJob printEvenNumbersJob = new PrintEvenNumbersJob(lock); PrintOddNumbersJob printOddNumbersJob = new PrintOddNumbersJob(lock); Thread thread1 = new Thread(printEvenNumbersJob); Thread thread2 = new Thread(printOddNumbersJob); thread2.start(); thread1.start(); } } 

你尝试过使用信号量吗? 它更容易,因为你不需要担心调用wait和notify的顺序(如果你在等待之前调用notify,它就会“丢失”)

示例代码:

 import java.util.concurrent.*; public class Test { private final Semaphore oddJobPermits = new Semaphore(0); private final Semaphore evenJobPermits = new Semaphore(1); private class EvenJob implements Runnable { public void run() { for (int i = 0; i < 10; i++) { try { evenJobPermits.acquire(); System.out.println(i * 2); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { oddJobPermits.release(); } } } } private class OddJob implements Runnable { public void run() { for (int i = 0; i < 10; i++) { try { oddJobPermits.acquire(); System.out.println(i * 2 + 1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { evenJobPermits.release(); } } } } public void run() { new Thread(new EvenJob()).start(); new Thread(new OddJob()).start(); } public static void main(String[] args) { new Test().run(); } } 

我相信你需要一个裁判:

 public class Referee { private boolean evensTurn = true; public void waitMyTurn(boolean even) { synchronized(this) { while (even != evensTurn) { try { wait(); } finally { } } } } public void done() { synchronized(this) { evensTurn = !evensTurn; notify(); } } } public class PrintEvenNumbersJob implements Runnable { private Referee referee; public PrintEvenNumbersJob(Referee referee) { this.referee = referee; } @Override public void run() { for (int i = 0; i <= 10; i += 2) { referee.waitMyTurn(true); System.out.println(i); referee.done(); } } } public class PrintOddNumbersJob implements Runnable { private Referee referee; public PrintOddNumbersJob(Referee referee) { this.referee = referee; } @Override public void run() { for (int i = 0; i <= 10; i += 2) { referee.waitMyTurn(false); System.out.println(i); referee.done(); } } } 

我试过并测试了这段代码。 它使用信号量工作

 public class TestSemaphore { public static void main(String[] args) throws Exception { AtomicInteger count = new AtomicInteger(); Semaphore s = new Semaphore(1, true); Semaphore t = new Semaphore(1, true); OddNumberThread oThread = new OddNumberThread(count, s, t); EvenNumberThread eThread = new EvenNumberThread(count, s, t); eThread.start(); oThread.start(); } static class EvenNumberThread extends Thread { private AtomicInteger count; private Semaphore s, t; public EvenNumberThread(AtomicInteger pCount, Semaphore pS, Semaphore pT) { super("Even"); count = pCount; s = pS; t = pT; } @Override public void run() { // Make this thread wait until even thread starts, Order will be incorrect if removed these lines. s.acquireUninterruptibly(); while (count.intValue() <= 10) { try { // Double checking to make it work s.acquireUninterruptibly(); System.out.println(getName() + " " + count.getAndIncrement()); } finally { t.release(); } } } } static class OddNumberThread extends Thread { private AtomicInteger count; private Semaphore s, t; public OddNumberThread(AtomicInteger pCount, Semaphore pS, Semaphore pT) { super("Odd"); count = pCount; s = pS; t = pT; } @Override public void run() { // Start this thread first and start printing, Order will be incorrect if removed these lines. t.acquireUninterruptibly(); s.release(); while (count.intValue() <= 10) { try { t.acquireUninterruptibly(); System.out.println(getName() + " " + count.getAndIncrement()); } finally { s.release(); } } } } }