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

时间:2014-04-10 00:24:41

标签: java multithreading

我创建了两个可运行的作业: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();

}

}

3 个答案:

答案 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();
                }
            }
        }
    }
}