多线程等待唤醒机制

示例代码取自传智播客毕向东老师25天Java基础教程,添加了一些观测打印代码,便于理解分析。对于进程分析理解纯粹个人理解,刚学Java没多久,难免有错,仅供参考,如果大神们发现错误,希望能帮忙指出,也帮我走出错误的理解。

先贴代码

class Res{
	String name;
	String sex;
	boolean flag=false;
}
class Input implements Runnable{
	private Res r;
	public Input(Res r) {
		this.r=r;
	}
	public void run() {
		int k=0;
		int a=0;//设定线程中有限次循环参数,便于观测运行数据
		while (a<5) {	//设定循环5次
			synchronized(r) {//设定同一锁
				if(r.flag)
					try {
						System.out.println("设置参数休眠");//用于观测本线程是否进入休眠
						r.wait();
						} catch (Exception e)
				{}
			if(k==0) {				
				r.name="Mike";
				r.sex="man";
				System.out.println("wozai mikezheli");//用于观测本是否进行此处成员变量赋值
			}else {	
				r.name="丽丽";
				r.sex="女女女女女女";
				System.out.println("我在 丽丽这里");//用于观测本是否进行此处成员变量赋值
			}
			a++;
			k=(k+1)%2;
			r.flag=true;
			r.notify();
			}
			
		}		
	}	
}
class Output implements Runnable{
	private Res r;
	Output(Res r){
		this.r=r;
	}
	public void run() {
		int b=0;
		while (b<5) {	
			synchronized(r) {
				if(!r.flag)
					try {
						System.out.println("打印参数休眠*****");//用于观测本线程是否进入休眠
						r.wait();
						} catch (Exception e)
				{}
			System.out.println(Thread.currentThread().getName()+r.name+"------"+r.sex);
			b++;
			r.flag=false;
			r.notify();
			}
			
		}		
	}	
}

public class InOutput {
	public static void main(String[] args) {
		Res r=new Res();
		Input in=new Input(r);
		Output out=new Output(r);
		Thread t1=new Thread(in);
		Thread t2=new Thread(out);
		t1.start();	
		t2.start();			
	}
}

运行结果:1、

wozai mikezheli
打印输出线程b Mike------man
打印参数休眠*****
我在 丽丽这里
打印输出线程b 丽丽------女女女女女女
打印参数休眠*****
wozai mikezheli
打印输出线程b Mike------man
打印参数休眠*****
我在 丽丽这里
打印输出线程b 丽丽------女女女女女女
打印参数休眠*****
wozai mikezheli
打印输出线程b Mike------man
这是出现最多的一种结果。首先赋值线程a启动,进入while循环,经同步锁进入同步代码块中,if(r.flag)判定,线程a未进入等待,直接进行if(k==0)判定,分别赋值Mike和man,此时和输出我们设定的观测语句“wozai mikezheli”,运行完接下来的语句且唤醒线程b,结束同步代码块。注意:此时线程a与b都是就绪状态,都可执行!!由结果可知,线程a再次抢夺到运行资质(NB啊),经同步锁进入同步代码块中,if(r.flag)判定,线程a进入等待(白抢了),同时放弃已占有的同步锁资源。线程b经同步锁进入同步代码块,经if(!r.flag)判断,线程b未进行等待。执行代码输出语句“打印输出线程b Mike------man”,运行完接下来的语句且唤醒线程a,结束同步代码块。此时a与b又都进入到就绪状态,抢夺执行权。由结果知b抢到了,但由于判断条件的参数改变,只能去等待,a执行赋值后唤醒b,结束同步代码块。再次竞争。。。。不管哪次竞争结果如何,如果刚执行完的线程抢到,由于参数设置的改变,都只能进入等待,对外表现为两线程交替执行。如果俩线程都处于就绪状态,竞争应该一直存在,未必只发生在俩线程都在同步代码块外面的时候,只不过,某一线程即使争到了也进不去同步锁或只能进入等待。以上分析大概率是错的,对于编程知道的太少了,只是现阶段的个人理解。
还有一种比较特别的结果(运行很多次会出现):
打印参数线程b休眠*****
wozai mikezheli
打印输出线程b Mike------man
打印参数线程b休眠*****
我在 丽丽这里
设置参数线程a休眠
打印输出线程b 丽丽------女女女女女女
打印参数线程b休眠*****
wozai mikezheli
设置参数线程a休眠
打印输出线程b Mike------man
打印参数线程b休眠*****
我在 丽丽这里
设置参数线程a休眠
打印输出线程b 丽丽------女女女女女女
打印参数线程b休眠*****
wozai mikezheli
打印输出线程b Mike------man

虽然线程a在主线程中先启动,线程b后启动,但是在第一次的竞争中还是输了,唉。。

学习Java三十多天,对于编程知识所知太少,分享只为交流个人理解,仅供参考,难免有错。希望有大神如果发现我理解中的错误,一定指出来!

对了,上面应该是等待,不是休眠!!


猜你喜欢

转载自blog.csdn.net/luhongzheng/article/details/80044017