Java:如何让2个线程交替使用一种方法

时间:2018-07-24 13:15:16

标签: java multithreading

Threads的新功能。

我有2个线程,希望它们交替使用一种方法。因此线程1执行该方法,然后等待。然后线程2唤醒线程1并执行该方法。然后线程1唤醒线程2并执行方法等。 但是我莫名其妙地陷入了僵局,我也不明白为什么。

public class NewT extends Thread{


public void print(NewT x)
{

    synchronized(this)
    {

        System.out.println("x"+x);
        notifyAll();
        try {
            wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


}

public void run()
{

    for(int i=0;i<10;i++)
    {
        print(this);                
    }


}

public static void main(String[] args) {
    // TODO Auto-generated method stub

    NewT one = new NewT();
    NewT two = new NewT();


    one.start();
    two.start();




}

}

3 个答案:

答案 0 :(得分:4)

由于synchronizedthis上,每个线程都在锁定自己的对象,实际上没有同步;他们正在等待一个永远不会发生的事件。

更新:

正如某人指出的那样,仅使用公共lock对象是不够的,因为两个线程最终都将等待。

这是一个解决方案:

private static Object lock = new Object();
private static NewT previous;

public static void print(NewT x) throws InterruptedException
{
    synchronized(lock) {
        while (previous == x) {
            lock.wait();
        }
        System.out.println("x"+ x);
        previous = x;
        lock.notifyAll();
    }
}

答案 1 :(得分:0)

在公用/共享对象上共享时,

Wait()notify()notifyAll()可以正常工作。在您的情况下,您是在通知自己(相同的线程实例)并等待不确定的时间。结果,JVM无法在2个条目后打印。

示例代码:

package ThreadsTricks;

/**
 *
 * @author pcu
 */

public class PrintOddEven {

boolean odd;
int count = 1;
int MAX = 20;

public void printOdd() {
    synchronized (this) {
        while (count < MAX) {
            System.out.println("Checking odd loop");

            while (!odd) {
                try {
                    System.out.println("Odd waiting : " + count);
                    wait();
                    System.out.println("Notified odd :" + count);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println("Odd Thread :" + count);
            count++;
            odd = false;
            notify();
        }
    }
}

public void printEven() {

    try {
      //  Thread.sleep(1000);
    } catch (Exception e1) {
        e1.printStackTrace();
    }
    synchronized (this) {
        while (count < MAX) {
            System.out.println("Checking even loop");

            while (odd) {
                try {
                    System.out.println("Even waiting: " + count);
                    wait();
                    System.out.println("Notified even:" + count);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Even thread :" + count);
            count++;
            odd = true;
            notify();

        }
    }
}

public static void main(String[] args) {

    PrintOddEven oddEven= new PrintOddEven();
    oddEven.odd = true;
    Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            oddEven.printEven();

        }
    });
    Thread t2 = new Thread(new Runnable() {

        @Override
        public void run() {
            oddEven.printOdd();

        }
    });

    t1.start();
    t2.start();

    try {
        t1.join();
        t2.join();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

这是我的第一个答案,如果有任何疑问,请告诉我。

答案 2 :(得分:0)

我在您的代码中看到的问题是您没有要锁定的共享对象,并且您的一个线程将永远等待(因为另一个线程已完成其活动并继续前进...)。我个人认为这里没有僵局。

这应该会有所帮助,但是我建议使用java.util.concurrent软件包以获得更好的选择。我个人不建议使用waitnotify / notfiyAll

import java.time.Instant;

public class AlternatingThreads {

    public static void main(String[] args) {
        Object lock = new Object();
        NewT one = new NewT(lock);
        NewT two = new NewT(lock);

        one.start();
        two.start();
    }

    public static class NewT extends Thread {
        private Object lock;

        public NewT(Object lock) {
            this.lock = lock;
        }

        public void print(NewT x) {
            synchronized (lock) {
                System.out.println(Instant.now().getNano() + "ns x-" + x);
                lock.notifyAll();

                try {
                    // timeout depends on how long you need for the activity to complete.
                    lock.wait(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public void run() {
            for (int i = 0; i < 10; i++) {
                print(this);
            }
            System.out.println(Instant.now().getNano() + "ns Final-" + this);
        }
    }
}

这将产生以下输出

573000000ns x-Thread[Thread-1,5,main]
576000000ns x-Thread[Thread-2,5,main]
576000000ns x-Thread[Thread-1,5,main]
576000000ns x-Thread[Thread-2,5,main]
576000000ns x-Thread[Thread-1,5,main]
576000000ns x-Thread[Thread-2,5,main]
576000000ns x-Thread[Thread-1,5,main]
576000000ns x-Thread[Thread-2,5,main]
576000000ns x-Thread[Thread-1,5,main]
576000000ns x-Thread[Thread-2,5,main]
576000000ns x-Thread[Thread-1,5,main]
576000000ns x-Thread[Thread-2,5,main]
576000000ns x-Thread[Thread-1,5,main]
576000000ns x-Thread[Thread-2,5,main]
576000000ns x-Thread[Thread-1,5,main]
577000000ns x-Thread[Thread-2,5,main]
577000000ns x-Thread[Thread-1,5,main]
577000000ns x-Thread[Thread-2,5,main]
577000000ns x-Thread[Thread-1,5,main]
577000000ns x-Thread[Thread-2,5,main]
577000000ns Final-Thread[Thread-1,5,main]
677000000ns Final-Thread[Thread-2,5,main]

Process finished with exit code 0
  

注意:如果没有100ms的超时,线程2将永远等待。