通知如何在Java线程中工作?

时间:2013-08-26 13:31:01

标签: java multithreading wait notify

我是新手在java中使用线程。我有一个简单的读写器问题,当一个作家进入一个线程时,读者会等待作者完成。

然而,当我运行我的程序时,我发现我的线程没有收到通知?这是为什么?

我的代码如下:

public class ReaderWriter  {

Object o = new Object();
volatile boolean writing;
Thread readerThread = new Thread( "reader") {

    public void run() {

        while(true) {
            System.out.println("reader starts");
            if(writing) {
            synchronized (o) {
                try {
                    o.wait();
                    System.out.println("Awaked from wait");
                } catch (InterruptedException e) {                      
                    e.printStackTrace();
                }

            }
        }

            System.out.println( "reader thread working "+o.hashCode());

        }

    }
};
Thread writerThread = new Thread("writer" ) {
    public void run() {
        System.out.println( " writer thread");
        try {
            synchronized (o) {
                writing = true;
                System.out.println("writer is working ..  ");
                Thread.sleep(10000);                    
                writing = false;
                o.notify();
                System.out.println("reader is notified");
            }


        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

public static void main(String[] args) {
    ReaderWriter rw=new ReaderWriter();
    rw.readerThread.start();

    rw.writerThread.start();

}

}

5 个答案:

答案 0 :(得分:4)

问题在于synchronized (o)功能。

  

synchronized函数使线程同步并在那里进行   它一次只对对象o执行一个线程。于是   而writing的值为真。它不允许第二个胎面   readerThread执行synchronized (o)

中的readerThread      

您正在获得无限循环,因为没有终止声明。
  查看here以了解线程何时终止

请查看此代码以了解有关同步功能的更多信息

synchronized(object) {
   // statements to be synchronized
}
  

这里,object是对正在同步的对象的引用。一个   synchronized块确保调用作为其成员的方法   只有在当前线程成功输入后才会出现对象   对象的监视器

阅读此内容以查看通知方法

JavaSW中的Object类有三个最终方法,允许线程就资源的锁定状态进行通信。这些方法是 wait(),notify()和notifyAll()。线程通过具有该资源实例的同步块获取特定资源的锁。假设一个线程要求另一个线程在对资源起作用之前对资源执行某个操作。该线程可以在资源上同步并在资源上调用wait()方法。 这表示该主题将一直等到通知它可以继续采取行动。

  

wait()方法可以将可选的超时值作为参数。   如果使用此值,则表示线程将等待直到   它被通知或者它将在超时值后继续执行   已经过去了。

如果一个线程需要在另一个线程对资源进行操作之前对资源执行任务(并且另一个线程正在通过资源上的wait()方法等待),则线程需要在资源上进行同步。它可以在资源上执行其操作。

为了在完成这些操作后通知等待线程,将调用资源上的notify()方法。这通知等待线程它可以继续行动。如果多个线程正在等待资源,则无法保证哪个线程将被授予对资源的访问权限。如果需要唤醒所有等待的线程,则可以在资源上调用notifyAll()方法。

答案 1 :(得分:1)

问题是writing在事先通知时设置为false。

Thread.sleep()不会唤醒其他等待的线程。

答案 2 :(得分:1)

writing设置为true时,编写器线程始终对您的监视器对象进行锁定。这就是在writing设置为true时,永远不会输入读者线程中的同步块的原因。

synchronized (o) { // Thread aquires lock on monitor o. writing is false.
    writing = true; // writing is true, lock still held.
    System.out.println("Writer is working...");
    Thread.sleep(1000); // Thread sleeps while holding lock.
    writing = false; // writing is changed back to false, lock still held.
    o.notify();
    System.out.println("Reader is notified");
} // Here lock is released, writing is false.

writing在获取锁定之前设置为false,在释放锁定时设置为false。锁定时,读取器线程中的同步块将不会输入:

while (true) {
    if (writing) {
        synchronized (o) { // Lock always held by writer when writing=true.
            try {
                o.wait();
                System.out.println("Awaked from wait");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

答案 3 :(得分:0)

感谢您的合作和宝贵的建议,我在代码中做了一些改动

public class ReaderWriter  {

Object o = new Object();
volatile boolean writing;
Thread readerThread = new Thread( "reader")  {

    public void run() {
        System.out.println("reader starts");

            synchronized (o) {
                    System.out.println("reader aquire the lock");
                    while(writing) {
                        try {                               
                            System.out.println("Reader goes to wait ....");
                            o.wait();                               
                            System.out.println("Awaked from wait");
                        } catch (InterruptedException e) {                      
                            e.printStackTrace();
                        }
                    }
                    while(!writing) {
                        //do something  
                        System.out.println("hiiiiiiii");
                    }
                    System.out.println("reader release the lock");  
                }
        }

    };

Thread writerThread = new Thread("writer" ) {
    public void run() {
        System.out.println( "writer starts");
        try {
            writing = true;
            synchronized (o) {                  
                System.out.println("writer aquire the lock");
                Thread.sleep(10000);        
                o.notify();                 
                System.out.println("reader is notified");
                System.out.println("writer release the lock");
            }
            writing = false;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

public static void main(String[] args) {
    ReaderWriter rw=new ReaderWriter();
    rw.readerThread.start();        
    rw.writerThread.start();

}

}

现在我发现了一个非常有趣的事情,即“等待时才等待”,只有当读者首先获得锁定并且在校正之后我才会在同步块之外写入= true和write = false,以便在读取器获取锁定之后编写器来改变写入标志因此读者等待并释放写入锁定,编写器获取锁定执行Thread.sleep并通知读者并因此释放锁定给读者。读取器唤醒并发现写入标志被写入设置为false,因此读者开始执行其操作。

答案 4 :(得分:0)

There can be only two cases when writer thread first enters its critical section or when reader thread enters first since by no means you are stopping one to sleep for other to start first.

1) In first case when writer thread enters critical section first synchronized block locks the object o and after waking up from sleep you notify but you are not releasing lock explicitly till sync block ends which unlocks the object automatically .So even if notification is sent inside block reader thread wont be able to take the lock .So after syn block of your writer thread is over you reader thread would run uninterrupted assuming there is no interrupt from third thread .

2) In second case when  you reader thread is scheduled by scheduler to run first it will obtain a lock and on finding flag false it will enter infinite loop of printing hi on output console and its is infinite since you have take lock of object and entered infinite loop which makes writer thread wait indefinitely on reader thread  

Correcting your code as below for reader thread 

synchronized (o) {
    System.out.println("reader aquire the lock");
    if(writing) {
        try {                               
            System.out.println("Reader goes to wait ....");
                            System.out.println("Awaked from wait");
        } catch (InterruptedException e) {                      
            e.printStackTrace();
        }
    }
    else{
        //do something 
        o.notify(); 
        o.wait(); // in this case only reader release the lock would only be printed and if block wont be executed
    }
    System.out.printn("reader release the lock");  
}