线程(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可以通过时时的监控系统的内存使用情况,随时监视垃圾回收 ...
随机推荐
- Codeforces Gym101522 D.Distribution of Days-算日期 (La Salle-Pui Ching Programming Challenge 培正喇沙編程挑戰賽 2017)
D.Distribution of Days The Gregorian calendar is internationally the most widely used civil calendar ...
- Qt小结
(1)#include 报错fatal error: QHostInfo:No such file or directory, 解决办法 在.pro文件中添加 QT += core gui netwo ...
- 轻量i3wm配置使用笔记 -- 主题切换器(j4-make-config)
快速切换主题 j4-make-config介绍: j4-make-config脚本可以方便地在几组"主题"之间切换,还可以根据当前工作的环境,轻松地从几个不同的配置部分组合一个完整 ...
- mac与linux服务器之间使用ssh互通有无
1. 在mac上没有找到好用的shell图形界面的软件,但也是有办法的,使用ssh公钥达到互相有无目的 2.场景是mac连A(linux,以下简称A)服务器 3.登陆mac shell ,按comma ...
- ie8 不能加载dll的问题解决
请问是在打开IE的时候提示无法加载DLL文件吗? 请尝试重置IE: 1. 关闭所有Internet Explorer窗口. 2. 单击开始,点击运行,输入inetcpl.cpl,按回车. 3. 点击高 ...
- git-ssh配置和使用
https://segmentfault.com/a/1190000002645623 1.设置Git的user name和email:(如果是第一次的话) $ git config --global ...
- 如何破解linux用户帐号密码二
转载 0x01 前言: 今天拿了个linux的主机,提下来了,以前提成root之后就没深入过,这次想着先把root密码破解出来: 以前交洞的时候只是单纯证明存在/etc/passwd和/etc/sha ...
- SQLServer-----SQLServer 2008 R2安装
- SSO单点登录系列2:cas客户端和cas服务端交互原理动画图解,cas协议终极分析
落雨 cas 单点登录 一.用户第一次访问web1应用. ps:上图少画了一条线,那一条线,应该再返回来一条,然后再到server端,画少了一步...谢谢提醒.而且,重定向肯定是从浏览器过去的.我写的 ...
- 新安装的金蝶K3软件,初始化后,在基础资料中对于币别,科目,部门,客户等资料均无法新增,无法引出,等操作,K3CASysSet.dll
新装K3,新建的帐套.导入科目点菜单或新增button均无反应,币别.客户等辅助核算项目也新增也无法保存. 在电脑上新安装的金蝶K3软件.初始化后.在基础资料中对于币别,科目,部门,客户等资料均无法新 ...