Java中的线程间通信

什么是轮询,它有什么问题?

反复测试条件直到其变为真的过程称为轮询。

轮询通常是借助循环来实现的,以检查特定条件是否为真。如果为真,则将采取某些措施。这浪费了许多CPU周期,并使实现效率低下。
例如,在一个经典的排队问题中,一个线程正在产生数据而另一个线程正在消耗数据。

Java多线程如何解决这个问题?
为了避免轮询,Java使用三种方法,即wait(),notify()和notifyAll()。
所有这些方法最终都属于对象类,因此所有类都具有它们。它们只能在同步块中使用。

  • wait()-它告诉调用线程放弃锁定并进入睡眠状态,直到其他线程进入同一监视器并调用notify()为止。
  • notify()-唤醒一个在同一对象上调用wait()的单个线程。应该注意的是,调用notify()实际上并没有放弃对资源的锁定
  • notifyAll()-唤醒同一对象上所有调用wait()的线程。

一个简单的Java程序来演示这三种方法

// Java program to demonstrate inter-thread communication 
// (wait(), join() and notify()) in Java 
import java.util.Scanner; 
public class threadexample 
{ 
    public static void main(String[] args) 
                           throws InterruptedException 
    { 
        final PC pc = new PC(); 
  
        // Create a thread object that calls pc.produce() 
        Thread t1 = new Thread(new Runnable() 
        { 
            @Override
            public void run() 
            { 
                try
                { 
                    pc.produce(); 
                } 
                catch(InterruptedException e) 
                { 
                    e.printStackTrace(); 
                } 
            } 
        }); 
  
        // Create another thread object that calls 
        // pc.consume() 
        Thread t2 = new Thread(new Runnable() 
        { 
            @Override
            public void run() 
            { 
                try
                { 
                    pc.consume(); 
                } 
                catch(InterruptedException e) 
                { 
                    e.printStackTrace(); 
                } 
            } 
        }); 
  
        // Start both threads 
        t1.start(); 
        t2.start(); 
  
        // t1 finishes before t2 
        t1.join(); 
        t2.join(); 
    } 
  
    // PC (Produce Consumer) class with produce() and 
    // consume() methods. 
    public static class PC 
    { 
        // Prints a string and waits for consume() 
        public void produce()throws InterruptedException 
        { 
            // synchronized block ensures only one thread 
            // running at a time. 
            synchronized(this) 
            { 
                System.out.println("producer thread running"); 
  
                // releases the lock on shared resource 
                wait(); 
  
                // and waits till some other method invokes notify(). 
                System.out.println("Resumed"); 
            } 
        } 
  
        // Sleeps for some time and waits for a key press. After key 
        // is pressed, it notifies produce(). 
        public void consume()throws InterruptedException 
        { 
            // this makes the produce thread to run first. 
            Thread.sleep(1000); 
            Scanner s = new Scanner(System.in); 
  
            // synchronized block ensures only one thread 
            // running at a time. 
            synchronized(this) 
            { 
                System.out.println("Waiting for return key."); 
                s.nextLine(); 
                System.out.println("Return key pressed"); 
  
                // notifies the produce thread that it 
                // can wake up. 
                notify(); 
  
                // Sleep 
                Thread.sleep(2000); 
            } 
        } 
    } 
} 

输出:

producer thread running
Waiting for return key.
Return key pressed
Resumed

如果您仍然对为什么我们在消耗线程中使用了通知感到困惑,请尝试将其删除并再次运行您的程序。正如您现在必须已经注意到的那样,该程序永远不会终止。
这样做的原因很简单-当您在生产线程上调用wait时,它继续等待并且从未终止。由于程序一直运行到其所有线程终止,因此它将一直运行。
解决这个问题还有第二种方法。您可以使用wait()的第二种变体。

void wait(long timeout) 

这将使调用线程仅在指定的时间内休眠。

posted @ 2020-10-27 21:00  我要去巴萨  阅读(133)  评论(0编辑  收藏  举报