android多线程通讯,Android-Java多线程通讯(生产者 消费者)&10条线程对-等待唤醒/机制的管理...

上一篇博客 Android-Java多线程通讯(生产者 消费者)&等待唤醒机制 是两条线程(Thread-0 / Thread-1) 在被CPU随机切换执行;

而今天这篇博客是,在上一篇博客Android-Java多线程通讯(生产者 消费者)&等待唤醒机制 的基础上,扩大规模增加10条线程去执行 生产者 消费者;

注意:?? 上一篇博客是两条线程在执行(生产者 消费者)例如:当Thread-0 锁.wait(); 等待 冻结后,  Thread-1 锁.notify(); 唤醒的一定是Thread-0(因为Thread-1 锁.notify(); 后

会在线程池里面 根据同步锁??找到冻结wait();的线程,而在共享的同步锁??中只有Thread-0),所以根据同步锁 就找到了 Thread-0;  唤醒成功。

所以根据以上分析,所以两条线程去执行生产者 消费者 是没有问题的:

案例一(两条线程去执行生产者 消费者);

packageandroid.java.thread16;/*** 描述资源*/

classRes {/*** name 是共享数据,被Thread-0 Thread-1公用使用*/

privateString name;/*** id 是共享数据,被Thread-0 Thread-1公用使用*/

private intid;/*** flag 是共享数据,被Thread-0 Thread-1公用使用*/

private boolean flag; //定义标记 默认第一次为false

/*** 对操作共享数据的地方加入同步锁的方式来解决安全问题

* public synchronized(this) void put(String name) {*/

public synchronized voidput(String name) {/*** 生产之前判断标记*/

if (!flag) {//开始生产

id += 1;this.name = name + " 商品编号:" +id;

System.out.println(Thread.currentThread().getName()+ "生产者 生产了:" + this.name);//生产完毕

/*** 修改标记*/flag= true;/*** 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的*/notify();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

/*** 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了*/

try{

wait();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

} catch(InterruptedException e) {

e.printStackTrace();

}

}

}/*** 对操作共享数据的地方加入同步锁的方式来解决安全问题

* public synchronized(this) void put(String name) {*/

public synchronized voidout() {/*** 消费之前判断标记*/

if(flag) {//开始消费

System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.name);//消费完毕

/*** 修改标记*/flag= false;/*** 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的*/notify();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

/*** 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了*/

try{

wait();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

} catch(InterruptedException e) {

e.printStackTrace();

}

}

}

}/*** 描述生产者任务*/

class ProduceRunnable implementsRunnable {/*** 此变量已经不是共享数据了,因为:

* new Thread(produceRunnable).start();

* new Thread(consumeRunnable).start();

*

* 所以:Thread-0有自己的res Thread-1也有自己的res*/

privateRes res;

ProduceRunnable(Res res) {this.res =res;

}/*** 执行线程任务*/@Overridepublic voidrun() {for (int i = 0; i < 20; i++) {

res.put("面包??");

}

}

}/*** 描述消费者任务*/

class ConsumeRunnable implementsRunnable {/*** 此变量已经不是共享数据了,因为:

* new Thread(produceRunnable).start();

* new Thread(consumeRunnable).start();

*

* 所以:Thread-0有自己的res Thread-1也有自己的res*/

privateRes res;

ConsumeRunnable(Res res) {this.res =res;

}/*** 执行线程任务*/@Overridepublic voidrun() {for (int i = 0; i < 20; i++) {

res.out();

}

}

}/*** 多线程通讯案例*/

public classThreadCommunicationDemo {public static voidmain(String[] args) {//创建资源对象

Res res = newRes();//创建生产者任务

ProduceRunnable produceRunnable = newProduceRunnable(res);//创建消费者任务

ConsumeRunnable consumeRunnable = newConsumeRunnable(res);//启动生产者任务

newThread(produceRunnable).start();//启动消费者任务

newThread(consumeRunnable).start();

}

}

执行结果,和谐了 生产一个 消费一个:

ca3f213f74b0867d89c068de9f69487a.gif

以上案例一,由于只有两条线程去执行生产者 消费者,所以 锁.notify(); 唤醒的线程只有一个,所以 以上案例一是没有问题的;

案例二:以下就使用10条线程去 执行生产者 消费者,会出现 锁.notify(); 把自身线程唤醒,出现混乱错误??

packageandroid.java.thread18;/*** 描述资源*/

classRes {/*** name 是共享数据,被Thread-0 Thread-1公用使用*/

privateString name;/*** id 是共享数据,被Thread-0 Thread-1公用使用*/

private intid;/*** flag 是共享数据,被Thread-0 Thread-1公用使用*/

private boolean flag; //定义标记 默认第一次为false

/*** 对操作共享数据的地方加入同步锁的方式来解决安全问题

* public synchronized(this) void put(String name) {*/

public synchronized voidput(String name) {/*** 生产之前判断标记*/

if (!flag) {/*** 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了*/

try{

wait();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

} catch(InterruptedException e) {

e.printStackTrace();

}

}//开始生产

id += 1;this.name = name + " 商品编号:" +id;

System.out.println(Thread.currentThread().getName()+ "生产者 生产了:" + this.name);//生产完毕

/*** 修改标记*/flag= false;/*** 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的*/notify();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

}/*** 对操作共享数据的地方加入同步锁的方式来解决安全问题

* public synchronized(this) void put(String name) {*/

public synchronized voidout() {/*** 消费之前判断标记*/

if(flag) {/*** 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了*/

try{

wait();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

} catch(InterruptedException e) {

e.printStackTrace();

}

}//开始消费

System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.name);//消费完毕

/*** 修改标记*/flag= true;/*** 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的*/notify();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

}

}/*** 描述生产者任务*/

class ProduceRunnable implementsRunnable {/*** 此变量已经不是共享数据了,因为:

* new Thread(produceRunnable).start();

* new Thread(consumeRunnable).start();

*

* 所以:Thread-0有自己的res Thread-1也有自己的res*/

privateRes res;

ProduceRunnable(Res res) {this.res =res;

}/*** 执行线程任务*/@Overridepublic voidrun() {while(true) {

res.put("面包??");

}

}

}/*** 描述消费者任务*/

class ConsumeRunnable implementsRunnable {/*** 此变量已经不是共享数据了,因为:

* new Thread(produceRunnable).start();

* new Thread(consumeRunnable).start();

*

* 所以:Thread-0有自己的res Thread-1也有自己的res*/

privateRes res;

ConsumeRunnable(Res res) {this.res =res;

}/*** 执行线程任务*/@Overridepublic voidrun() {while (true) {

res.out();

}

}

}/*** 多线程通讯案例 -->>> 10条线程对 多生产 多消费 对等待/唤醒的管理控制*/

public classThreadCommunicationDemo {public static voidmain(String[] args) {//创建资源对象

Res res = newRes();//创建生产者任务

ProduceRunnable produceRunnable = newProduceRunnable(res);//创建消费者任务

ConsumeRunnable consumeRunnable = newConsumeRunnable(res);//启动生产者任务

newThread(produceRunnable).start();newThread(produceRunnable).start();newThread(produceRunnable).start();newThread(produceRunnable).start();newThread(produceRunnable).start();//启动消费者任务

newThread(consumeRunnable).start();newThread(consumeRunnable).start();newThread(consumeRunnable).start();newThread(consumeRunnable).start();newThread(consumeRunnable).start();newThread(consumeRunnable).start();

}

}

执行结果:

出现异常的原因:

由于有10个线程在执行 生产者 消费者,就会造成 notify();混乱 例如:生产者 生产完毕后 Thread-5>>>wait(); Thread-5>>>notify(); 的时候有可能会把自身线程Thread-5唤醒;

由于有10个线程在执行 生产者 消费者,就会造成 notify();混乱 例如:消费者 消费完毕后 Thread-8>>>wait(); Thread-8>>>notify(); 的时候有可能会把自身线程Thread-8唤醒;

当把自身线程Thread-*唤醒的时候,就已经是?错误的,异常的程序了;

5831a3e24133a7ab0b0156ee88d7b44e.gif

案例三,主要是解决以上案例二的问题:

【修改点1:把if 修改成 while】

【修改点2:修改成notifyAll】

packageandroid.java.thread18;/*** 描述资源*/

classRes {/*** name 是共享数据,被Thread-0 Thread-1公用使用*/

privateString name;/*** id 是共享数据,被Thread-0 Thread-1公用使用*/

private intid;/*** flag 是共享数据,被Thread-0 Thread-1公用使用*/

private boolean flag; //定义标记 默认第一次为false

/*** 对操作共享数据的地方加入同步锁的方式来解决安全问题

* public synchronized(this) void put(String name) {*/

public synchronized voidput(String name) {/*** 生产之前判断标记,【修改点1:把if 修改成 while】*/

while (!flag) {/*** 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了*/

try{

wait();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

} catch(InterruptedException e) {

e.printStackTrace();

}

}//开始生产

id += 1;this.name = name + " 商品编号:" +id;

System.out.println(Thread.currentThread().getName()+ "生产者 生产了:" + this.name);//生产完毕

/*** 修改标记*/flag= false;/*** 唤醒所有 【修改点2:修改成notifyAll】*/notifyAll();//注意:?? wait(); notify(); notifyAll 这些必须要有同步锁包裹着

}/*** 对操作共享数据的地方加入同步锁的方式来解决安全问题

* public synchronized(this) void put(String name) {*/

public synchronized voidout() {/*** 消费之前判断标记,【修改点1:把if 修改成 while】*/

while(flag) {/*** 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了*/

try{

wait();//注意:?? wait(); notify(); 这些必须要有同步锁包裹着

} catch(InterruptedException e) {

e.printStackTrace();

}

}//开始消费

System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.name);//消费完毕

/*** 修改标记*/flag= true;/*** 唤醒所有 【修改点2:修改成notifyAll】*/notifyAll();//注意:?? wait(); notify(); notifyAll 这些必须要有同步锁包裹着

}

}/*** 描述生产者任务*/

class ProduceRunnable implementsRunnable {/*** 此变量已经不是共享数据了,因为:

* new Thread(produceRunnable).start();

* new Thread(consumeRunnable).start();

*

* 所以:Thread-0有自己的res Thread-1也有自己的res*/

privateRes res;

ProduceRunnable(Res res) {this.res =res;

}/*** 执行线程任务*/@Overridepublic voidrun() {while(true) {

res.put("面包??");

}

}

}/*** 描述消费者任务*/

class ConsumeRunnable implementsRunnable {/*** 此变量已经不是共享数据了,因为:

* new Thread(produceRunnable).start();

* new Thread(consumeRunnable).start();

*

* 所以:Thread-0有自己的res Thread-1也有自己的res*/

privateRes res;

ConsumeRunnable(Res res) {this.res =res;

}/*** 执行线程任务*/@Overridepublic voidrun() {while (true) {

res.out();

}

}

}/*** 多线程通讯案例 -->>> 10条线程对 多生产 多消费 对等待/唤醒的管理控制*/

public classThreadCommunicationDemo {public static voidmain(String[] args) {//创建资源对象

Res res = newRes();//创建生产者任务

ProduceRunnable produceRunnable = newProduceRunnable(res);//创建消费者任务

ConsumeRunnable consumeRunnable = newConsumeRunnable(res);//启动生产者任务

newThread(produceRunnable).start();newThread(produceRunnable).start();newThread(produceRunnable).start();newThread(produceRunnable).start();newThread(produceRunnable).start();//启动消费者任务

newThread(consumeRunnable).start();newThread(consumeRunnable).start();newThread(consumeRunnable).start();newThread(consumeRunnable).start();newThread(consumeRunnable).start();newThread(consumeRunnable).start();

}

}

执行结果:10条线程对-等待唤醒/机制的管理 比较OK??

56001d5c8d3c0bfcb3a23216316f4457.gif

1.修改出现问题的代码:由于每次锁.wait(); 之前是使用if判断,if判断会引发 "if (flag) {此时CPU就在这里临时阻塞了,当再次获得CPU执行权时 就属于异常了}"   所以修改每次锁.wait(); 之前判断 使用循环while(flag){} while会往回循环判断,就可以解决此问题了;

2.修改出现问题的代码:锁.notify();后 会唤醒同步锁??里面冻结的任意一个线程,有可能唤醒自身线程,有可能唤醒其他线程,现在由于加了while(flag){}来判断,唤醒自身线程会拦截了,不用担心自身线程被唤醒了,就算唤醒自身线程也会拦截;        现在愁的是(锁.notify(); 如果唤醒自身线程,就无法唤醒其他线程了)  所以解决方案是:全部唤醒 notifyAll(); 反正已经修改了while(falg){} 判断标记拦截方式了

notify();   notifyAll();    wait();   必须在 synchronized{里面使用,因为 这些方法需要 同步锁}

原文:https://www.cnblogs.com/android-deli/p/10244441.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值