Java线程_Notify,NotifyAll,Wait方法

       怎么办,好几天没写博客了,心里感觉不踏实。水一篇吧,水水更健康Java线程_Notify,NotifyAll,Wait方法。在看Java线程这本书的电子版,看到第四章notify、wait、notifyAll这几个方法,前面的notify和wait还好,比较简单,就是需要注意的是notify和wait方法必须放在同步代码中。可是为什么要这样呢?原因是如果不将notify和wait放到同步代码中的话,他们之间可能会产生竞态条件。现设有两个线程,如果不将notify和wait放在同步代码中可能发生如下情况:

       一、第一个线程检查条件,确定需要等待。
       二、第二个线程设定条件。
       三、第二个线程调用notify()方法,本次调用因为没有其他的等待线程而直接返回。
       四、第一个线程调用wait()。

       附上一段关于notify和wait的Android代码:

package com.wly.testwait_notify;


import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {

	int count = 0;
	Button b;
	CountThread countThread;
	Handler handler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			b.setText(msg.arg1 + "");
		}
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		b = new Button(this);
		b.setText("0");
		this.setContentView(b);
		
		countThread = new CountThread();
		countThread.start();
		
		b.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				if(countThread.isAlive()) {
					countThread.wakeup();
				}
			}
		});
	}

	class CountThread extends Thread {

		@Override
		public void run() {
			super.run();
			while(count < 20) {
				sendMsg();
				try {
					sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
		//发送通知,并进入等待状态,注意wait()只能位于synchronized代码块中
		public synchronized void sendMsg() {
			Message msg = new Message();
			msg.arg1 = count ++;
			handler.sendMessage(msg);
			if(count % 5 == 0) {
				try {
					System.out.println("--等待10秒--");
					wait(10000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
		/**
		 * 唤醒线程,注意notify()只能位于synchronized代码块中
		 */
		public synchronized void wakeup() {
			notify();
		}
	}
}

      说出来有点好笑的是,笔者以前想在Android中用wait()结果因为没有放到同步代码块中,导致一运行就报错,还以为Android中不能用wait呢!咳咳,,不要笑啦,进入今天正题NotifyAll。可能是最近办公室比较吵得原因吧(抢票的抢票,聊天的聊天),使得笔者静不下心来,于是一个notifyAll盯着看了好久才看懂。

      还是一样分析,为什么要有notifyAll,他和notify有什么区别吗?notifyAll用来唤醒一个对象上的多个等待线程。就是说首先这个对象有多个线程等待着使用该对象,其次就是要唤醒所有的线程,让他们去竞争对象上的锁。这里需要注意一下的是:虽然所有该对象上的等待线程都被唤醒了,但他们还需要获得对象上的锁才能向下运行。于是当调用notifyAll后还是只有那个获取到了锁的线程才能继续往下运行。好了,一段notifyAll的测试代码:

package com.wly.javathread.chap4;

/**
 * 测试notifyAll方法
 * 
 * @author wly
 * 
 */
public class TestNotifyAll implements Runnable {

	static ResourcePool mPool;
	
	public static void main(String[] args) {
		
		ResourcePool pool = new ResourcePool();
		
		System.out.println("总资源数:" + pool.resource_max);

		TestNotifyAll tn_1 = new TestNotifyAll(pool);
		TestNotifyAll tn_2 = new TestNotifyAll(pool);
		TestNotifyAll tn_3 = new TestNotifyAll(pool);
		TestNotifyAll tn_4 = new TestNotifyAll(pool);
		
		new Thread(tn_1).start();
		new Thread(tn_2).start();
		new Thread(tn_3).start();
		new Thread(tn_4).start();
		
	}
	
	@Override
	public void run() {
		while(true) {
			mPool.getResource(2);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			mPool.freeResource(1);
		}
	}

	public TestNotifyAll(ResourcePool pool) {
		this.mPool = pool;
	}
	
	static class ResourcePool {
		int resource_max = 10; //资源最大数量
		int resource_count = 0; //当前占用资源数量
		
		/**
		 * 获取资源
		 * @param num
		 */
		public synchronized void getResource(int num) {
			if((resource_count + num) <= resource_max) { //有可用资源,领取使用
				resource_count += num;
				System.out.println("线程" + Thread.currentThread().getId() + "拿到2个资源");
				System.out.println("剩余资源数:" + (resource_max -resource_count));
			} else { //无可用资源,等
				try {
					System.out.println("资源数量不够,线程" + Thread.currentThread().getId() + ":进入等待状态");
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
		/**
		 * 释放资源
		 * @param num
		 */
		public synchronized void freeResource(int num) {
			if(num <= (resource_count)) {
				resource_count -= num;
				System.out.println("释放" + num + "个资源,当前剩余资源" + (resource_max-resource_count));
				notifyAll();
			} 
		}
	}
}

        运行结果如下:

总资源数:10
线程9拿到2个资源
剩余资源数:8
线程11拿到2个资源
剩余资源数:6
线程8拿到2个资源
剩余资源数:4
线程10拿到2个资源
剩余资源数:2
释放1个资源,当前剩余资源3
线程9拿到2个资源
剩余资源数:1
释放1个资源,当前剩余资源2
线程11拿到2个资源
剩余资源数:0
释放1个资源,当前剩余资源1
资源数量不够,线程8:进入等待状态
释放1个资源,当前剩余资源2
线程10拿到2个资源
剩余资源数:0
释放1个资源,当前剩余资源1
资源数量不够,线程9:进入等待状态
释放1个资源,当前剩余资源2
线程11拿到2个资源
剩余资源数:0
释放1个资源,当前剩余资源1
资源数量不够,线程8:进入等待状态
释放1个资源,当前剩余资源2
线程10拿到2个资源
剩余资源数:0
释放1个资源,当前剩余资源1
资源数量不够,线程11:进入等待状态
释放1个资源,当前剩余资源2
线程9拿到2个资源
剩余资源数:0
释放1个资源,当前剩余资源1
资源数量不够,线程8:进入等待状态
释放1个资源,当前剩余资源2
线程10拿到2个资源
剩余资源数:0

       可能运行结果需要仔细看才能看出流程,主要就是释放资源时通知所有等待线程,若此时某个等待线程抢到了锁会进行资源请求,或者进入等待状态(资源不够时)。

      O啦~~~

      转载请保留出处:http://blog.csdn.net/u011638883/article/details/18322537

      谢谢!!

Java线程_Notify,NotifyAll,Wait方法

上一篇:试用JPush极光消息推送


下一篇:同步锁、互锁(死锁)