怎么办,好几天没写博客了,心里感觉不踏实。水一篇吧,水水更健康。在看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
谢谢!!