Java同步:synchronized,wait(),notify()

时间:2018-02-13 12:37:51

标签: java multithreading synchronization

我正在尝试理解Java中的线程间通信,并通过使用:wait()notify()notifyAll()方法来了解支持。

为了使线程执行任何这些方法,线程需要是对象的lock的所有者,线程正在调用这些方法(任何这些)。除此之外,所有这些方法都需要在synchronized块/方法中。到目前为止还不错。

我试图实现一个程序,其中一个线程打印奇数,其他线程打印偶数。

该计划正常运作,但与此同时,它引起了更多疑虑。

以下是我实施的程序的完整源代码。

PrintEvenNumThread.java //打印偶数

package com.example.multithr.implrun;

import com.example.common.ObjectToWaitOn;

public class PrintEvenNumThread implements Runnable {

    private ObjectToWaitOn objectToWaitOn;

    public PrintEvenNumThread(ObjectToWaitOn objectToWaitOn) {
        this.objectToWaitOn = objectToWaitOn;
    }

    @Override
    public void run() {

    int numToPrint = 2;

    for (;;) {
        synchronized (objectToWaitOn) {
            while(objectToWaitOn.getPrintEvenOrOdd() != 2) {
                try {
                    objectToWaitOn.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }   
            }
                objectToWaitOn.print("EvenThread",numToPrint);
                numToPrint += 2; // Generate next even number
                objectToWaitOn.setPrintEvenOrOdd(1);
                objectToWaitOn.notifyAll();
            }
        }
    }
}

PrintOddNumsThread.java //打印奇数

package com.example.multithr.implrun;

import com.example.common.ObjectToWaitOn;

public class PrintOddNumsThread implements Runnable {

    private ObjectToWaitOn objectToWaitOn;

    public PrintOddNumsThread(ObjectToWaitOn objectToWaitOn) {
        this.objectToWaitOn = objectToWaitOn;
    }

    @Override
    public void run() {
        int numToPrint = 1;

        for(;;) {

            synchronized(objectToWaitOn) {

                while(objectToWaitOn.getPrintEvenOrOdd() != 1) {  
                    try {
                        objectToWaitOn.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                objectToWaitOn.print("OddThread", numToPrint);
                numToPrint += 2; // Generate next odd number
                objectToWaitOn.setPrintEvenOrOdd(2);
                objectToWaitOn.notifyAll();
            }
        }
    }
}

ObjectToWaitOn.java //"共享"线程间通信的对象

package com.vipin.common;

public class ObjectToWaitOn {

    private int printEvenOrOdd;

    public ObjectToWaitOn(int printEvenOrOdd) {
        this.printEvenOrOdd = printEvenOrOdd;
    }

    public int getPrintEvenOrOdd() {
        return printEvenOrOdd;
    }

    public void setPrintEvenOrOdd(int printEvenOrOdd) {
        this.printEvenOrOdd = printEvenOrOdd;
    }

    public void print(String byThread, int numToPrint) {
        System.out.println(byThread + ": " +numToPrint);
    }
}

PrintEvenOddNumsMainApp.java

package com.example.multithr.main.app1;

import com.example.common.ObjectToWaitOn;
import com.example.multithr.implrun.PrintEvenNumThread;
import com.example.multithr.implrun.PrintOddNumsThread;

    public class PrintEvenOddNumsMainApp {

        public static void main(String[] args) {

            ObjectToWaitOn obj = new ObjectToWaitOn(1); // 1 == odd; 2 == even

            PrintEvenNumThread printEvenNumThread = new PrintEvenNumThread(obj);
            PrintOddNumsThread printOddNumsThread = new PrintOddNumsThread(obj);

            Thread evenNum = new Thread(printEvenNumThread);
            Thread oddNum = new Thread(printOddNumsThread);

            evenNum.start();
            oddNum.start();
        }
    }

我怀疑是:

1)当这些线程中的任何一个通过调用对象notifyAll()上的objectToWaitOn(在这些线程之间共享)释放锁定时,它是否立即释放锁定?我有这个疑问,因为这些线程基于synchronized对象在objectToWaitOn块中;所以即使一个线程调用notifyAll(),也不应该保持锁定,因为它处于同步块中?

2)当线程通过调用wait()上的objectToWaitOn处于等待状态时,如果其他线程通过调用notifyAll()释放锁,则等待线程是否等待< / strong>锁定发布或其他什么?从synchronized块出来的线程是否会释放对它所拥有的对象的锁定;所以在上面的示例中,如果一个帖子在objectToWaitOn上保持锁定并且从synchronized块出来,那么它就不会释放objectToWaitOn的锁定,并且不应该在onclick="hello('"+ data.name + "');" 。基于此,其他线程唤醒了吗?

有谁能帮我澄清这些疑惑?

1 个答案:

答案 0 :(得分:5)

  

是否立即释放锁定?

不,它没有。线程继续执行同步块中的下一个语句。

  

它是否仍然保持锁定,因为它处于同步块中?

是的,它应该。调用notify / notifyAll方法的线程必须持有锁并继续保持它,直到它正常离开同步块或发生异常:

  
      
  • 如果Block 的执行正常完成,则监视器将被解锁并且synchronized语句正常完成。
  •   
  • 如果由于任何原因执行Block 突然,则显示器将被解锁并且同步语句因同样的原因突然完成。
      <子> JLS-14.19
  •   

notify / notifyAll方法将此监视器上等待的线程 1 的状态从State.WAITING更改为State.RUNNABLE。当线程被唤醒时,他们可以参与获取锁定。

进入监视器,其中一些 2 可能会获得STATE.BLOCKED状态,并等到另一个线程释放锁定。请注意,它不需要来自持有锁的线程的任何通知。

  

唤醒的线程将无法继续,直到当前线程放弃对此对象的锁定。唤醒的线程将以通常的方式与可能主动竞争同步的任何其他线程竞争在这个对象上;例如,被唤醒的线程在下一个锁定此对象的线程中享有没有可靠的特权或劣势
  <子> docs

1.如果是notify,则它是一个任意选择的线程 2.或者所有这些 - 如果通知的线程持有显示器。