Java中的线程间通信

先决条件: Java中的多线程 , 在Java中同步

null

Java中的线程间通信是一种机制,其中一个线程在其关键部分暂停运行,另一个线程被允许进入(或锁定)要执行的同一关键部分。

注: 线程间通信也称为 爪哇的合作。

什么是民意调查,其结果是什么 有问题吗?

反复测试一个条件直到其变为真的过程称为轮询。轮询通常通过循环来实现,以检查特定条件是否为真。如果这是真的,就会采取某种行动。这会浪费很多CPU周期,使实现效率低下。

例如,在一个经典的排队问题中,一个线程正在生成数据,另一个线程正在消耗数据。

Java多线程如何解决这个问题?

为了避免轮询,Java使用了三种方法:, wait()、notify()和notifyAll()。 所有这些方法都属于对象类,因此所有类都有它们。它们只能在同步块中使用。

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

图片[1]-Java中的线程间通信-yiteyi-C++库

例子:

一个简单的Java程序来演示这三种方法。请注意,此程序可能只在脱机IDE中运行,因为它包含在多个点进行输入。

JAVA

// Java program to demonstrate inter-thread communication
// (wait(), join() and notify())
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

说明:

虽然看起来很可怕,但如果你经历两次,那就是小菜一碟。

  1. 在主类中,将创建一个新的PC对象。
  2. 它使用两个不同的线程(即t1和t2)运行PC对象的生成和消费方法,并等待这些线程完成。

让我们了解一下我们的生产和消费方法是如何工作的。

  • 首先,使用同步块可以确保一次只运行一个线程。此外,因为在消费循环的开始有一个sleep方法,所以生产线程会得到一个kickstart。
  • 当在product方法中调用wait时,它会做两件事。首先,它释放它在PC对象上的锁。其次,它使生产线程处于等待状态,直到所有其他线程终止。它可以再次获取PC对象上的锁,其他一些方法通过调用同一对象上的notify或notifyAll来唤醒它。
  • 因此,我们看到,一旦调用wait,控件就会转移到consumer线程,并打印“Waiting for return key”
  • 按下返回键后,consume方法调用notify()。它还做两件事——首先,与wait()不同,它不会释放对共享资源的锁定。因此,为了获得所需的结果,建议只在方法末尾使用notify。第二,它通知等待的线程,它们现在可以唤醒,但只有在当前方法终止之后。
  • 正如您可能已经注意到的,即使在通知之后,控件也不会立即传递给生产线程。原因是我们称之为线程。在notify()之后睡眠()。我们已经知道,消费线程在PC对象上持有一个锁。另一个线程在释放锁之前无法访问它。因此,只有在消费线程完成其睡眠时间并自行终止之后,生产线程才能收回控制权。
  • 暂停2秒后,程序终止,直至完成。

如果您仍然不明白我们为什么在consume thread中使用notify,请尝试删除它并再次运行您的程序,因为您现在肯定已经注意到,该程序从未终止。

原因很简单。当您调用product线程等待时,它一直在等待,从未终止。由于一个程序一直运行到其所有线程都已终止,因此它会继续运行。

解决这个问题还有第二种方法。您可以使用wait()的第二个变体。

void wait(long timeout) 

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

本文由 Rishabh Mahrsee .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以使用 写极客。组织 .查看你在GeekSforgeks主页上的文章,并帮助其他极客。

如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享