Java 通知在不同对象中运行的线程
我仔细阅读了Oracle文档,没有找到解决我的问题的设计模式解决方案。我有两个匿名线程,一个需要通知另一个Java 通知在不同对象中运行的线程,java,multithreading,design-patterns,concurrency,thread-safety,Java,Multithreading,Design Patterns,Concurrency,Thread Safety,我仔细阅读了Oracle文档,没有找到解决我的问题的设计模式解决方案。我有两个匿名线程,一个需要通知另一个 public static void main(String[] args) { MyClass obj = new MyClass(); obj.a(); obj.b(); } MyClass有两个不同的函数,每个函数启动一个匿名线程。B个人希望被他的妻子A吵醒 public class MyClass{ public MyClass(){
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.a();
obj.b();
}
MyClass有两个不同的函数,每个函数启动一个匿名线程。B个人希望被他的妻子A吵醒
public class MyClass{
public MyClass(){
}
public void a() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("A: I am going to sleep");
try {
Thread.sleep(1000);
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public void b() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("B: I am going to sleep. A, please wake me up.");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("B: Thank you A for waking me up!");
}
}).start();
}
}
不幸的是,B永远睡不着,不能被他的妻子A吵醒
public class MyClass{
public MyClass(){
}
public void a() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("A: I am going to sleep");
try {
Thread.sleep(1000);
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public void b() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("B: I am going to sleep. A, please wake me up.");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("B: Thank you A for waking me up!");
}
}).start();
}
}
程序的输出:
A: I am going to sleep
B: I am going to sleep. A, please wake me up.
A: I slept one full day. Feels great.
A: Hey B, wake up!
我知道A和B在两个不同的匿名线程对象中运行,所以A只能通知其他A(床上没有其他妻子,所以通知功能在这里是无用的)
此问题的正确设计模式是什么 这些线程之间需要共享一个类变量。线程A首先锁定锁,然后要进入睡眠状态,线程B锁定它。螺纹A通过解锁锁来唤醒螺纹B。也可以使用。基本点是在单个对象监视器上调用
wait()
和notify()
或notifyAll()
,以进行线程同步。我会这样做的
在我的代码中,MyClass
具有a()
和b()
实例方法synchronized
。因此,调用这些方法的实例将成为隐式监视器。我正在与2个可运行的实现共享MyClass
(即obj
)的相同实例
public class MyClass{
public MyClass(){
}
public synchronized void a() {
System.out.println("A: I am going to sleep");
try {
Thread.sleep(5000);
wait();
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void b() {
System.out.println("B: I am going to sleep. A, please wake me up.");
notifyAll();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("B: Thank you A for waking me up!");
}
public static void main(String [] args) {
MyClass obj = new MyClass();
Thread t1 = new Thread(new RunnableImpl(obj, true));
Thread t2 = new Thread(new RunnableImpl(obj, false));
t1.start();
t2.start();
}
}
class RunnableImpl implements Runnable {
boolean callA;
MyClass obj;
public RunnableImpl(MyClass obj, boolean callA) {
this.callA = callA;
this.obj = obj;
}
@Override
public void run() {
if(callA) {
obj.a();
}
else {
obj.b();
}
}
}
您需要线程共享一个公共对象来调用上的wait()/notify()方法。现在您在this
对象上调用它们,这两种情况下都是它们自己的线程对象
还要注意,您还需要在公共对象上同步,因此您不能只在run()方法上放置synchronized。为了能够从一个线程唤醒另一个线程,它们需要与公共对象同步。例如,您可以使用调用线程的MyClass对象:
public void a() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("A: I am going to sleep");
synchronized(MyClass.this)
{
try {
Thread.sleep(1000);
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
MyClass.this.notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
public void b() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("B: I am going to sleep. A, please wake me up.");
synchronized(MyClass.this)
{
System.out.println("B: Thank you A for waking me up!");
}
}
}).start();
}
这将使a()
的线程获得锁并休眠1000毫秒。同时会调用b()
,但它的线程必须等到a()
的线程释放锁后才能打印,谢谢你叫醒我
如果您总是在b()
之前调用a()
,这将起作用。否则,如果b()
首先获得了锁,那么谢谢你叫醒我
将在a()
睡眠
之前执行
当前,代码中的锁位于两个不同的对象上-由a
创建的Runnable
在自身上有一个锁,与b
相同,因此当调用notifyAll
时,没有对象等待锁通知
同步块中的线程.sleep
也有问题
更改您的代码,以便在使用synchronized
关键字时获得锁,如下所示:
public void a()
{
new Thread(
new Runnable()
{
@Override
public void run()
{
try
{
System.out.println("A: I am going to sleep");
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
synchronized(MyClass.this)
{
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
MyClass.this.notifyAll();
}
}
}
).start();
}
public void b()
{
new Thread(
new Runnable()
{
@Override
public void run()
{
synchronized(MyClass.this)
{
System.out.println("B: I am going to sleep. A, please wake me up.");
try
{
MyClass.this.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("B: Thank you A for waking me up!");
}
}
}
).start();
}
代码中有两个问题
正如其他人所建议的那样。使用时需要使用相同的锁
通知并等待。您正在使用不同的对象来等待和通知
是它们各自的线程实例。
下面的代码是使用MyClass.this运行的
试一试{
等待();
}捕捉(中断异常e){
即使使用了正确的锁,代码也存在另一个问题
假设您试图通过线程遇到。在线程A中睡眠(1000)。此问题
被称为错过通知,即threadA可以在threadB执行其wait()方法之前完成,这将导致threadB无限休眠
以上两个问题的解决方案都是使用闩锁。请尝试CountDownLatch
见下文
import java.util.concurrent.CountDownLatch;
public class MyClass{
CountDownLatch latch = new CountDownLatch(1);
public MyClass(){
}
public void a() {
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("A: I am going to sleep");
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}).start();
}
public void b() {
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("B: I am going to sleep. A, please wake me up.");
try {
latch.await();
} catch (InterruptedException e) {}
System.out.println("B: Thank you A for waking me up!");
}
}).start();
}
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.a();
obj.b();
}
}
拜托,难道你不能让其他人自己做作业吗?如果你为他们写下工作代码,他们将如何学习。@Kayaman如果OP没有代码,我就不会发布答案。OP尝试了一些东西,所以我发布了一个可能的答案。我想这是怎么回事?@sanbhat为什么我们在b中有notifyAll()呢?a()
和b()
方法在同一监视器下同步obj
。因此notifyAll()
将通知等待a()
或b()的所有线程