0

我想运行两个共享方法的线程来打印出一些东西。我想要这个作为输出:

a b a b a b 

第一个线程打印一个'a',第二个线程打印一个'b'。我设法打印了一次,但我不能包含一个适当的循环来交换打印件。

我写了这段代码来执行这个:

public void run() {
    while(i<10) {
        synchronized(this) {
            while (turn!=turn) {
                try {
                    turn=!turn;
                    wait();
                    sleep(10);
                }
                catch(InterruptedException ie){}
            }

            printThreadOutput();
            turn=!turn;
            i++;
            notifyAll();
        }
    }
}

有什么建议么?

4

3 回答 3

1

一个简单的解决方案是使用java.util.concurrent.locks.Lock,它将执行所需的所有等待和通知操作:

public class ThreadTest {

    private static final Lock lock = new ReentrantLock();

    public static final void main(String[] args) {
        Runnable aRun;
        Runnable bRun;

        aRun = new Runnable() {
            public void run() {
                while (true) {
                    lock.lock();
                    System.out.println("a");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    lock.unlock();
                }
            }
        };

        bRun = new Runnable() {
            public void run() {
                while (true) {
                    lock.lock();
                    System.out.println("b");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    lock.unlock();
                }
            }
        };

        Thread aThread = new Thread(aRun);
        Thread bThread = new Thread(bRun);
        aThread.start();
        bThread.start();
    }

}

如果不使用监视器,您可以这样做,但正如@noahz 谦虚地指出的那样,它使用了效率不高的自旋锁。

public class ThreadTest {

    private static volatile Boolean isATurn = true;

    public static void main(String[] args) {
        Runnable aRun;
        Runnable bRun;

        aRun = new Runnable() {
            public void run() {
                while (true) {
                    while (!isATurn) {
                    }
                    System.out.println("a");
                    isATurn = false;
                }
            }
        };

        bRun = new Runnable() {
            public void run() {
                while (true) {
                    while (isATurn) {
                    }
                    System.out.println("b");
                    isATurn = true;
                }
            }
        };

        Thread aThread = new Thread(aRun);
        Thread bThread = new Thread(bRun);
        aThread.start();
        bThread.start();
    }

}

据我所知,这可以保证不会出现死锁,但是如果其中一个线程没有终止,则可能会出现饥饿,因为另一个线程将等待它。但是,对于像这样的简单示例,这不应该构成问题。监视器也更喜欢使用轮询,但涉及程度略高。

于 2013-03-31T01:20:16.250 回答
1

现在是凌晨 3.30 点,我想睡觉。这就是我想出的:

class TurnHolder {

    private volatile int currentTurn;

    public void setNextTurn() {
    this.currentTurn = currentTurn^1;
    }

    public int getCurrentTurn() {
    return currentTurn;
    }
}

class Printer implements Runnable {

    private String toPrint;
    private TurnHolder sharedResource;
    private int turn;

    Printer(String toPrint, TurnHolder sharedResource, int turn) {
    this.toPrint = toPrint;
    this.sharedResource = sharedResource;
    this.turn = turn;
    }

    @Override
    public void run() {

    while (true) {
        synchronized (sharedResource) {
        if (sharedResource.getCurrentTurn() != turn)
            try {
            sharedResource.wait();
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
        System.out.println(toPrint);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sharedResource.setNextTurn();
        sharedResource.notifyAll();
        }
    }

    }

运行它的一种方法是:

TurnHolder sharedResource = new TurnHolder();

Printer printerA = new Printer("a", sharedResource, 0);
Printer printerB = new Printer("b", sharedResource, 1);

new Thread(printerA).start();
new Thread(printerB).start();

这样,您sharedResource将保留转弯的记忆并在其上进行同步,这样您就可以做与该转弯有关的事情,然后您可以切换转弯。这Thread.sleep只是为了让您以不错的速度看到打印。这System.out.println(toPrint);是你的printThreadOutput();

PS:欢迎提出如何改进代码的建议。

于 2013-03-31T01:29:51.747 回答
0
  1. 让其中一个线程在此之前 5 秒休眠。它将明确哪个是线程顺序。
  2. 循环没有执行,while因为它的条件总是false。完全删除内部while,你不需要它。
  3. turn不需要该变量。和将使线程轮流synchronizeThread.sleep(5)
  4. println抓的时候至少放一些InterruptedException
于 2013-03-31T01:20:11.740 回答