Java多线程中的wait和notifyAll

        想要直接看代码的可以跳过下面我对并发的简单理解,直接看代码(我已经加了注释,代码写的有问题还请诸位大神指出,以免误人子弟)。

        最近要用到Java多线程,才好好的看了一下多线程。谁知道这货写起来这么麻烦,还要考虑各种锁,还要考虑各种共享,各种交互。我就奇怪了,Java设计者怎么就不给程序员提供方便的同步机制,每次都要锁锁锁的,万一控制不好还死锁,妹的,简直不能忍。不过话说回来,Java的属性和方法可以是private、protected、public的,方法可以不用synchronized等等天性让它的并行安全性大大降低,并行处理也变得难上加难。

        这里的wait、notifyAll、notify是Object类的方法,分别对应条件对象Condition中的await、signalAll、signal方法。它们的字面意思是一样的,作用也差不多。

        这时你就要问了:我就想知道wait和notifyAll,你给我说Condition干嘛!其实是这样的:在synchronized出世前,Java程序员普遍采用显式加锁、显式附加锁的条件对象来解决并发问题。而Java1.0以后每个对象都有一个内部锁而且该锁有一个内部条件,所以可以用synchronized关键字来控制某个对象或方法的并发访问,这样也避免了过多显式地加锁和释放锁。所以synchronized是 Lock和Condition的一种特殊简写。

        condition.awit()<-->object.wait():当前线程被阻塞并放弃锁,进入该条件的等待集。直到另一个线程调用同一条件对象的signalAll()为止。(因此,当锁可用时并不一定能马上解除阻塞,还得等条件满足才行。这也是和那些单纯地等待锁的线程的区别)。

        condition.signalAll()<-->object.notifyAll():将所有线程从它的等待集中移出,使之成为可运行的,此时线程应再次测试一下该条件(通常利用while循环)。这里要注意一点signal()方法只会随机地移出某个等待线程而不是全部,所以如果某个线程没被signal通知到就会一直被阻塞容易出现死锁。

       object.wait()和object.notifyAll()方法跟上面说的condition类似,不过想要使用object.wait()和object.notifyAll()必须先获得object的对象锁(也就是放在synchronized代码块中)。好吧如果你不相信我,可以看一下其它大牛们写的关于object.wait()和object.notifyAll()的分析,看和condition.awit()是不是类似。

        好了,说了这么多,下面来看一下下面的代码:我就是单纯地想开一个子线程来完成一个循环处理的工作,我在主线程中能灵活控制这个子线程的开始、暂停/继续、结束。简单吧?对我一个24k纯菜鸟来说可真的不简单,下面是我的实现:

public class MainActivity {
	private String isCycleFlag[] = { "true" };// 是否要求循环,默认可以循环
	private String isDeadFlag[] = { "false" };// 是否要求线程退出,默认不退出

	class CycleThread extends Thread {
		public CycleThread(String name) {// 通过构造器给线程命名
			super(name);
		}

		public void run() {
			run_label: while (!Thread.currentThread().isInterrupted()) {// 这里可耻的利用了Java标签break
				synchronized (isDeadFlag) {// 获得isDeadFlag对象锁
					while (isDeadFlag[0].equals("true")) {// 如果要求线程死亡,直接break无限循环
						break run_label;// 跳出while就到了run方法的末尾,run方法执行完了,线程的使命也就完成了
						// return;
					}
				}
				synchronized (isCycleFlag) {// 获得isCycleFlag对象锁
					while (isCycleFlag[0].equals("false")) {// 如果要求循环终止,直接阻塞当前线程并释放对象锁
						try {
							System.out
									.println(getName() + " waiting 4 second!");
							isCycleFlag.wait();// 进入等待集,等着被“叫醒”
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					System.out.println(getName() + " start Cycle!");// 真正开始干活
				}
				try {
					Thread.sleep(1000);// 让它睡一秒再自动醒过来,为了更好地看到输出
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}// while
			System.out.println(getName() + " end!");// 线程干完活了
		}// run
	}// Thread class

	public void onResume() {
		synchronized (isCycleFlag) {// 获得isCycleFlag对象锁
			isCycleFlag[0] = "true";// 给isCycleFlag对象赋值
			isCycleFlag.notifyAll();// “叫醒”所有因为 要求循环终止 而阻塞的线程,继续循环
		}
	}

	public void onStop() {
		synchronized (isCycleFlag) {
			isCycleFlag[0] = "false";
			isCycleFlag.notifyAll();// 要求循环终止
		}
	}

	public void onDestory() {
		synchronized (isCycleFlag) {// 子线程此时可能被阻塞,这里先“叫醒”线程再终止它。(好吧,我承认我没想到怎么终止被阻塞的线程,只能先叫醒它)
			isCycleFlag[0] = "true";
			isCycleFlag.notifyAll();
		}
		synchronized (isDeadFlag) {
			isDeadFlag[0] = "true";
			isDeadFlag.notifyAll();
		}
	}

	public static void main(String[] args) throws InterruptedException {
		MainActivity test = new MainActivity();
		CycleThread cycleThread = test.new CycleThread("CycleThread");
		cycleThread.start();// 启动子线程(循环线程)
		try {
			Thread.sleep(4000);// 让主线程睡四秒,让子线程先运行着
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		test.onStop();// 要求循环终止

		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		test.onResume();// 要求继续循环

		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		test.onDestory();// 要求子线程停止
	}

}
就一个Java工程,里面一个MainActivity.java文件。所有的代码都在这了,大家可以运行试一下,有什么建议(或者要批评的)尽管说,我好学习一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值