简体   繁体   English

如何确保两个线程打印偶数为偶数,对于此实现,它先保持偶数然后是奇数?

[英]How to make sure two threads printing even odd numbers maintain even first then odd order for this implementation?

I have created two runnable jobs: PrintEvenNumbersJob and PrintOddNumbersJob and spawned two threads to execute these jobs. 我创建了两个可运行的作业:PrintEvenNumbersJob和PrintOddNumbersJob,并生成了两个线程来执行这些作业。 This seems to work perfectly fine! 这似乎工作得很好! But I smell something suspicious about this implementation. 但是我对这种实现感到有些怀疑。 Can I have some comments and advice on this implementation? 我可以对此实施提出一些意见和建议吗?

The problem that I see with this implementation is that the program terminates only when thread1 gains the lock to the object lock first otherwise it print the odd first even second order and doesn't terminate unless I supply yet another statement "lock.notify" after for statement in PrintEvenNumbersJob (as in this implementation). 我看到的这种实现的问题是,仅当线程1首先获得对对象锁的锁定时,程序才会终止,否则它将打印奇数第一个偶数二阶,并且不会终止,除非我在之后提供另一个语句“ lock.notify”用于PrintEvenNumbersJob中的语句(如此实现中所示)。 My question here is how to make sure that thread1 is executed first. 我的问题是如何确保先执行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();

}

}

Have you try using Semaphores? 您是否尝试过使用信号量? It's easier because you don't need to worry about the order that wait and notify are called (if you call notify before the wait, it's "lost") 这样比较容易,因为您不必担心等待和通知的调用顺序(如果在等待之前调用通知,则“丢失”)

Sample code: 样例代码:

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

}

I believe you will need a referee: 我相信您将需要一名裁判:

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

I tried and tested this code. 我尝试并测试了此代码。 It works using 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();
                }
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM