线程(while 和 if 剖析)
那存钱取钱为例:
要求实现一次存一次取的操作 不可出现连续存或连续取;
如果只有存钱和取钱各自只有一个线程在操作使用 if 的话可以满足要求:
package com.thread;
/**
* 模拟同步取款的问题
* @author dr
*
*/
public class ThreadTest {
public static void main(String[] args) {
final Account account = new Account();
//取出200
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<3;i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.getMoney(200);
}
}
}).start();
//存入300
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<3;i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.setMoney(300);
}
}
}).start();
}
}
class Account { private int balance = 1000;
private boolean setMoney = true;
public synchronized void getMoney(int count){
if(setMoney){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
int result =balance - count;
if(result >= 0){
balance = result;
System.out.println(Thread.currentThread().getName()+"取出:"+count+"元,剩余:"+balance);
}else{
System.out.println("余额不足...");
}
setMoney = true;
this.notify();
}
public synchronized void setMoney(int count){
if(!setMoney){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
balance += count;
System.out.println(Thread.currentThread().getName()+"存入:"+count+"元,剩余:"+balance);
setMoney = false;
this.notify();
} }
但是如果存钱和取钱包含多个线程的话 if 就不行 只有使用while才能满足条件
package com.thread;
/**
* 模拟同步取款的问题
* @author dr
*
*/
public class ThreadTest {
public static void main(String[] args) {
final Account account = new Account();
//取出200 两个取钱的线程
for(int i=0;i<2;i++){
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<3;i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.getMoney(200);
}
}
}).start();
}
//存入300 两个存钱的线程
for(int i=0;i<2;i++){
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<3;i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.setMoney(300);
}
}
}).start();
}
}
}
class Account { private int balance = 1000;
//先存钱
private boolean setMoney = true;
public synchronized void getMoney(int count){
while(setMoney){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
int result =balance - count;
if(result >= 0){
balance = result;
System.out.println(Thread.currentThread().getName()+"取出:"+count+"元,剩余:"+balance);
}else{
System.out.println("余额不足...");
}
setMoney = true;
this.notifyAll();
}
public synchronized void setMoney(int count){
while(!setMoney){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
balance += count;
System.out.println(Thread.currentThread().getName()+"存入:"+count+"元,剩余:"+balance);
setMoney = false;
this.notifyAll();
} }
分析:
有A、B、C、D四个线程 AB存钱线程,CD取钱线程,使用if的时候,假设A执行,看标志无需wait 执行完成后 改标志为 取 ,A B 都先获得执行权 但状态不符合,
处于等待状态 A B 无执行权, C获得执行权后 执行完成后 更改状态为存 同时唤醒 A ,D获得执行权也处于等待状态。
现在只有A有执行权 A执行完成后 更改标志 先唤醒 B,B此时无需检查标志了紧接执行存款 从而导致 出现连续两次 取款的情形
使用while的时候 ,虽然B被唤醒 但经while(flag) 又会 检查标志 使其处于等待状态 使用while 要使用notifyAll 否则会出现全部等待状态
线程(while 和 if 剖析)的更多相关文章
- pthread_create线程创建的过程剖析
http://blog.csdn.net/wangyin159/article/details/47082125 在Linux环境下,pthread库提供的pthread_create()API函数, ...
- Nginx 的线程池与性能剖析
http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt158 正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方 ...
- Android多线程研究(1)——线程基础及源代码剖析
从今天起我们来看一下Android中的多线程的知识,Android入门easy,可是要完毕一个完好的产品却不easy,让我们从线程開始一步步深入Android内部. 一.线程基础回想 package ...
- pthread_create线程创建的过程剖析(转)
概述 在Linux环境下,pthread库提供的pthread_create()API函数,用于创建一个线程.线程创建失败时,它可能会返回ENOMEM或EAGAIN.这篇文章主要讨论线程创建过程中碰到 ...
- Java线程池核心原理剖析
在系统开发时,我们经常会遇到“池”的概念.使用池一种以空间换时间的做法,通常在内存中事先保存一系列整装待命的对象,以供后期供其他对象随时调用.常见的池有:数据库连接池,socket连接池,线程池等.今 ...
- Nginx 的线程池与性能剖析【转载】
正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为此,NGIN ...
- Netty源码分析第2章(NioEventLoop)---->第4节: NioEventLoop线程的启动
Netty源码分析第二章: NioEventLoop 第四节: NioEventLoop线程的启动 之前的小节我们学习了NioEventLoop的创建以及线程分配器的初始化, 那么NioEvent ...
- 循序渐进 Jprofiler
一 Jprofiler 1 什么是Jprofiler JProfiler是一个全功能的Java剖析工具(profiler),专用于分析J2SE和J2EE应用程式.它把CPU.线程和内存的剖析组合在一个 ...
- JProfiler使用入门(一)——准备工作
JProfiler是一个全功能的Java剖析工具(profiler),主要用于检查和跟踪系统(限于Java开发的)的性能. JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收 ...
随机推荐
- CentOS 7 配置阿里云yum源
Test at Red Hat Enterprise Linux Server release 7.5 (Maipo) File localtion /etc/yum.repos.d/epel.rep ...
- luogu P2423 双塔
题目描述 2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难.为了纪念“911”事件,Mr. F决定自己用水晶来搭建一座双塔.Mr. F有N块水晶,每块 ...
- 盘点支持Orchard的.NET 4.5虚拟主机(虚拟空间)
Orchard作为.NET社区最为先进的开源项目之一,已经被越来越多的人使用, 由于它使用了最时髦的微软技术栈(.NET4.5),因此在 Win2008+和IIS7+ 的环境上运行最为完美, 而win ...
- C#获取程序所在的目录
有的时候,我们需要读取程序所在目录下的一些文件,最常见的写法是直接通过".\xxx.file"之类的相对路径来获取文件.虽然这种写法大多数的时候能正确工作,但却又一个很大的隐患:程 ...
- Geoserver跨域问题
1 Geoserver位war包,使用Tomcat发布的情况 由于geoserver为war形式,需要解决tomcat跨域问题,geoserver版本为2.9.1. (1)下载跨域war包 下载cor ...
- 研读:Shielding applications from an untrusted cloud with Haven
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdHJ1c3Ribw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...
- Spark原理小总结
1.spark是什么? 快速,通用,可扩展的分布式计算引擎 2.弹性分布式数据集RDD RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据 ...
- HM编码器代码阅读(14)——帧间预測之AMVP模式(二)predInterSearch函数
简单介绍 predInterSearch基本的工作是ME(运动预计)和MC(运动补偿). 函数中有一个bTestNormalMC变量.它表示是否进行正常的MC过程,正常的MC过程就是进 ...
- eletron 播放rtmp flash 播放器问题
1 安装 flash https://www.flash.cn/ 2 man.js 配置 参考 https://newsn.net/say/electron-flash-win.html 3 播放器 ...
- 一个JavaScript Function Outliner插件 第三个版本 让你的JavaScript代码也支持折叠
下面我只以英文的vs2008版本作为实例,演示一下打开vs2008 然后一次点击:Tools->Options (工具->选项)会弹出选项设置框在左边的树目录里展开Environment- ...