黑马程序员_多线程的线程间通信学习笔记

来源:互联网 发布:自定义端口范围 编辑:程序博客网 时间:2024/05/01 19:37

------- android培训、java培训、期待与您交流! ----------


1、线程间通信

其实就是多个线程在操作同一个资源。

但操作的动作不同。


2、等待唤醒机制

wait()和notify()方法是Object中的方法,不是Thread中的方法。(因为锁可以是任意对象)

wait()和notify()必须标识所属的监视器(锁)。


3、相关简单代码示例:

1)资源类定义

/** * 资源类 * @author CBY * */class Res {/** * 姓名 */private String name;/** * 性别 */private String sex;/** * 读写标识(true:标识已写,待读;false:标识已读,待写) */private boolean flag = false;/** * 写入(同步方法,锁为this对象) * @param name 姓名 * @param sex 性别 */public synchronized void set(String name,String sex) {//如果已写,待读(则进入等待)while(flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//被唤醒后,写入新数据this.name = name;this.sex = sex;//重新标识已写待读flag = true;//唤醒等待线程池中,最顶层的等待线程this.notify();}/** * 读取(同步方法,锁为this对象) */public synchronized void out() {//如果已读,待写(则进入等待)while(!flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//被唤醒后读取数据System.out.println(name + "..." + sex);//重新标识已读待写flag = false;//唤醒等待线程池中,最顶层的等待线程this.notify();}}

2)写入类定义

/** * 负责写入的类 * @author CBY * */class Input implements Runnable {//保存共享资源引用private Res r;//共享资源引用公构造器中传入Input(Res r) {this.r = r;}//写内容的标志位(不是关键点,仅用于验证)boolean b = true;@Overridepublic void run() {//不断调用写的方法while(true) {if(b) {r.set("丽丽", "女");b = false;} else {r.set("mike", "man");b = true;}}}}

3)读取类定义

/** * 负责读取的类 * @author CBY * */class Output implements Runnable {//保存共享资源引用private Res r;//共享资源引用公构造器中传入Output(Res r) {this.r = r;}@Overridepublic void run() {//不断调用读的方法while(true)r.out();}}

4)验证类定义

/** * 验证类 * @author CBY * */public class TestRes {public static void main(String[] args) {//新建共享资源Res r = new Res();//调用写线程new Thread(new Input(r)).start();//调用读线程new Thread(new Output(r)).start();}}

5)运行模型



4、JDK1.5以后

可用Lock替代synchronized;

用Condition替代了监视器方法的使用;

用Condition对象的方法await(),代替方法wait();

用Condition对象的方法signal(),代替方法notify();

用Condition对象的方法signalAll(),代替方法notifyAll()。

一个Lock,可以产生多个Condition。

修改后的资源类,eg:

/** * 资源类 * @author CBY * */class Res {/** * 姓名 */private String name;/** * 性别 */private String sex;/** * 读写标识(true:标识已写,待读;false:标识已读,待写) */private boolean flag = false;/** *  */private Lock lock = new ReentrantLock();private Condition writeCondition = lock.newCondition();private Condition readCondition = lock.newCondition();/** * 写入(同步方法,锁为this对象) * @param name 姓名 * @param sex 性别 */public void set(String name,String sex) {try{//加锁lock.lock();//如果已写,待读(则进入等待,记住,这边一定是用循环判断)while(flag) {try {//让“写Condition”进行等待writeCondition.await();} catch (InterruptedException e) {e.printStackTrace();}}//被唤醒后,写入新数据this.name = name;this.sex = sex;//重新标识已写待读flag = true;//让“读Condition”被唤醒readCondition.signalAll();} finally {//解锁lock.unlock();}}/** * 读取(同步方法,锁为this对象) */public void out() {try {//加锁lock.lock();//如果已读,待写(则进入等待,记住,这边一定是用循环判断)while(!flag) {try {//让“读Condition”进行等待readCondition.await();} catch (InterruptedException e) {e.printStackTrace();}}//被唤醒后读取数据System.out.println(name + "..." + sex);//重新标识已读待写flag = false;//唤醒等待线程池中,最顶层的等待线程writeCondition.signalAll();} finally {lock.unlock();}}}


5、停止线程

Thread对象中,原有所有线程的方法都已经过时。

当前,只有一种方法停止线程。那就是,控制线程结束。


6、守护线程

守护线程,又称后台线程。在前台线程全部结束后,守护线程也就结束了。

守护线程定义setDaemon(true)必须在start()方法前被调用。


7、join方法

抢占当前CPU执行权。

eg:

public static void main(String[] args) throws InterruptedException {//新建共享资源Res r = new Res();//调用写线程Thread t1 = new Thread(new Input(r));t1.start();//t1抢占了main的执行权,mian等到t1执行完之后,才会继续执行。//join用来临时加入线程执行t1.join();}


------- android培训、java培训、期待与您交流! ----------

0 0
原创粉丝点击