0 0

这个java程序,为什么一个notify唤醒了3个wait0

//主程序
class  Demo6
{
public static void main(String[] args)
{

Go1 q=new Go1();
Go2 qq=new Go2(q);
Go3 qqq=new Go3(q);
Come w=new Come(q);

q.start();
qq.start();
qqq.start();
w.start();

}
}
//线程1,打印1,等待,唤醒后打印一
class Go1 extends Thread
{
public void run()
{

synchronized (this)
{
System.out.println("1");
try
{
wait();
}
catch (Exception e)
{
}
}
System.out.println("一");

}

}
//线程2,打印2,等待,唤醒后打印二
class Go2 extends Thread
{
Go1 g;
Go2(Go1 g)
{
this.g=g;

}
public void run()
{

synchronized (g)
{
System.out.println("2");
try
{
g.wait();
}
catch (Exception e)
{
}
}
System.out.println("二");
}
}
//线程3,打印3,等待,唤醒后打印三
class Go3 extends Thread
{
Go1 g;
Go3(Go1 g)
{
this.g=g;

}
public void run()
{

synchronized (g)
{
System.out.println("3");
try
{
g.wait();
}
catch (Exception e)
{
}
}
System.out.println("三");
}
}
//唤醒线程
class Come extends Thread
{
Go1 r;

Come(Go1 r)
{
this.r=r;
}
public void run()
{
try
{
sleep(100);
}
catch (Exception e)
{
}
synchronized (r)
{
r.notify();
System.out.println("lock open");
}
}
}
2012年10月22日 21:36

5个答案 按时间排序 按投票排序

0 0

synchronized (g) 锁定的都是同一个Go1,r.notify();会解除synchronized (g) 和synchronized (this)的锁,当然有三个线程被唤醒了,如果每个线程都是不同Go1实例,就不会了。

2012年10月24日 22:10
0 0

如果一个线程对象最为锁对象,当线程执行完成后,会 notifyAll(); 其他线程.

原因:

Thread.exit() 方法

/**
     * This method is called by the system to give a Thread
     * a chance to clean up before it actually exits.
     */
    private void exit() {
	if (group != null) {
	    group.remove(this);
	    group = null;
	}
	// ...
    }


其中的 group.remove(this);

/**
     * Removes the specified Thread from this group.
     * @param t the Thread to be removed
     * @return if the Thread has already been destroyed.
     */
    void remove(Thread t) {
	synchronized (this) {
	    //...
	    if (nthreads == 0) {
		notifyAll();
	    }
            // ...
	}
    }


以上结论均为目测,无官方文档证实~~~~~~~

测试代码:
public class Test
{
	public static Lock	lock	= new Lock();

	public static void main(String[] args)
	{
		A a = new A();
		B b = new B();

		a.start();
		b.start();

		try
		{
			TimeUnit.SECONDS.sleep(3);
		}
		catch(InterruptedException e)
		{
			e.printStackTrace();
		}

		synchronized(lock)
		{
			try
			{
				System.out.println("catch lock");
				lock.start();
				System.out.println("notifyall");
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}

	static class A extends Thread
	{

		@Override
		public void run()
		{

			synchronized(lock)
			{
				System.out.println("a");
				try
				{
					lock.wait();
				}
				catch(InterruptedException e)
				{
					e.printStackTrace();
				}
				System.out.println("aa");
			}
		}
	}

	static class B extends Thread
	{

		@Override
		public void run()
		{

			synchronized(lock)
			{
				System.out.println("b");
				try
				{
					lock.wait();
				}
				catch(InterruptedException e)
				{
					e.printStackTrace();
				}
				System.out.println("bb");
			}

		}
	}

	static class Lock extends Thread
	{

	}
}

2012年10月23日 12:19
0 0

原因是共用的对象本身也是一个线程,所以notify的时候,如果被唤醒的是Go1的线程,那么Go2和Go3中的g.wait();也会跟着返回,所以相当于Go1,Go2,Go3都被唤醒,然后一起争夺锁。把共用的对象换成一个普通的对象就没有问题了。代码如下:

class  Demo6 
{ 

	public static void main(String[] args) 
	{ 
		Go g = new Go();
		Go1 q=new Go1(g); 
		Go2 qq=new Go2(g); 
		Go3 qqq=new Go3(g); 
		Come w=new Come(g); 

		q.start(); 
		qq.start(); 
		qqq.start(); 
		w.start(); 
	} 
}


class Go{
	
	
}



class Go1 extends Thread 
{ 
	Go g;
	Go1(Go g) 
	{ 
		this.g=g; 
	} 
	
	public void run() 
	{ 

		synchronized (g) 
		{ 
			System.out.println("1"); 
			try 
			{ 
				g.wait(); 
			} 
			catch (Exception e) 
			{ 
			} 
		} 
		System.out.println("一"); 
	} 
} 

class Go2 extends Thread 
{ 
	Go g; 
	Go2(Go g) 
	{ 
		this.g=g; 
	} 

	public void run() 
	{ 
		synchronized (g) 
		{ 
			System.out.println("2"); 
			try 
			{ 
				g.wait(); 
			} 
			catch (Exception e) 
			{ 
			} 
		} 
		System.out.println("二"); 
	} 
} 

class Go3 extends Thread 
{ 
	Go g; 
	Go3(Go g) 
	{ 
		this.g=g; 
	} 
	public void run() 
	{ 
		synchronized (g) 
		{ 
			System.out.println("3"); 
			try 
			{ 
				g.wait(); 
			} 
			catch (Exception e) 
			{ 
			} 
		} 
		System.out.println("三"); 
	} 
} 
 
class Come extends Thread 
{ 
	Go r; 

	Come(Go r) 
	{ 
		this.r=r; 
	} 
	public void run() 
	{ 
		try 
		{ 
			sleep(100); 
		} 
		catch (Exception e) 
		{ 
		} 
		synchronized (r) 
		{ 
			r.notify(); 
			System.out.println("lock open"); 
		} 
	} 
} 

2012年10月23日 11:21
0 0

测试了一下,情况应该是:
有时只唤醒一个,而只有在Go1 q先被唤醒的情况下,其他的才会被唤醒;
如果把同步的对象设为全局变量应该就会只唤醒一个。
怀疑是不是和对象的引用或者虚假唤醒有关系。

引用
在没有被通知、中断或超时的情况下,线程还可以唤醒一个所谓的虚假唤醒 (spurious wakeup)。虽然这种情况在实践中很少发生,但是应用程序必须通过以下方式防止其发生,即对应该导致该线程被提醒的条件进行测试,如果不满足该条件,则继续等待。

2012年10月23日 10:05
0 0

相关推荐

    41.线程间的通信-wait与notify-只唤醒一个线程或所有线程.mp4

    在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。

    Java wait和notify虚假唤醒原理

    主要介绍了Java wait和notify虚假唤醒,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    java 面试题 总结

    在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。...

    java笔试题大集合及答案(另附各大公司笔试题)

    60、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 答:有两种实现方法,分别是继承Thread类与实现Runnable接口 用synchronized关键字修饰同步方法 反对使用...

    Java多线程基础 线程的等待与唤醒(wait、notify、notifyAll)

    主要介绍了Java多线程基础 线程的等待与唤醒,需要的朋友可以参考下

    Java高级程序设计测试含答案.docx

    update() 在线程同步中,为了唤醒另一个等待的线程,使用下列方法 () [单选题] * A.sleep() B.wait() C.notify()(正确答案) D. join() Java高级程序设计测试含答案全文共40页,当前为第4页。Java提供以下哪个...

    Java多线程的等待唤醒机制代码演示通俗易懂

    生产者和消费者是一个十分经典的多线程协作模式 **常见方法:** - void wait() 当前线程等待,直到被其他线程唤醒 - void notify() 随机唤醒单个线程 - void notifyAll() 唤醒所有线程

    JAVA面试题集合面试技能大全

    当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常。违反语义规则包括2种情况。一种是JAVA类库内置的语义检查。例如数组下标越界,会引发IndexOutOfBoundsException;访问null的对象时会...

    Java-线程状态和等待唤醒机制和线程池

    创建一个老板线程(生产者):花了5秒做包子,做好包子之后,调用notify方法,唤醒顾客吃包子 注意: 顾客和老板线程必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行 同步使用的锁对象必须保证唯一 只有锁...

    超级有影响力霸气的Java面试题大全文档

    在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。...

    java多线程通信之等待唤醒机制

     唤醒在此对象监视器上等待的单个线程,如果所有线程都在此对象上等待,则会任意选择唤醒其中一个线程。  public final void wait()  当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,...

    Java中线程的等待与唤醒_动力节点Java学院整理

    在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。下面通过本文给大家介绍Java中线程的等待与唤醒知识,感兴趣的...

    java多线程系列(四)ReentrantLock的使用.docx

    一个condition对象的signal(signalAll)方法和该对象的await方法是一一对应的,也就是一个condition对象的signal(signalAll)方法不能唤醒其他condition对象的await方法 ReentrantLock类可以唤醒指定条件的...

    Java并发编程原理与实战

    使用Condition重写waitnotify案例并实现一个有界队列.mp4 深入解析Condition源码.mp4 实战:简易数据连接池.mp4 线程之间通信之join应用与实现原理剖析.mp4 ThreadLocal 使用及实现原理.mp4 并发工具类...

    锁、生产者与消费者.pdf

    notify():执行该方法的线程唤醒在等待池中等待的任意一个线程,把线程转到锁池中等待(注意锁池和等待池的区别) notifyAll():执行该方法的线程唤醒在等待池中等待的所有线程,把线程转到锁池中等待。 注意:上述...

    龙果java并发编程完整视频

    第32节使用Condition重写wait/notify案例并实现一个有界队列00:22:05分钟 | 第33节深入解析Condition源码00:21:15分钟 | 第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析...

    java并发编程

    第32节使用Condition重写wait/notify案例并实现一个有界队列00:22:05分钟 | 第33节深入解析Condition源码00:21:15分钟 | 第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析...

    龙果 java并发编程原理实战

    第32节使用Condition重写wait/notify案例并实现一个有界队列00:22:05分钟 | 第33节深入解析Condition源码00:21:15分钟 | 第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析...

    Java 并发编程原理与实战视频

    第32节使用Condition重写wait/notify案例并实现一个有界队列00:22:05分钟 | 第33节深入解析Condition源码00:21:15分钟 | 第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析...

Global site tag (gtag.js) - Google Analytics