我创建了两个可运行的作业:PrintEvenNumbersJob和PrintOddNumbersJob,并生成两个线程来执行这些作业。这似乎工作得很好!但我闻到了这个实施的可疑之处。我可以就此实施提出一些意见和建议吗?
我在这个实现中看到的问题是,只有当thread1首先获得对象锁的锁定时,程序才会终止,否则它会打印奇数的第一个偶数秒,并且除非我提供,否则不会终止另一个陈述" lock.notify"在PrintEvenNumbersJob中的for语句之后(如在此实现中)。我的问题是如何确保首先执行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();
}
}
答案 0 :(得分:1)
您尝试使用信号量吗?它更容易,因为你不需要担心调用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();
}
}
答案 1 :(得分:0)
我相信你需要一名裁判:
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();
}
}
}
答案 2 :(得分:0)
我试过并测试了这段代码。它使用Semaphore
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();
}
}
}
}
}