那存钱取钱为例:

  要求实现一次存一次取的操作 不可出现连续存或连续取;

  如果只有存钱和取钱各自只有一个线程在操作使用 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 剖析)的更多相关文章

  1. pthread_create线程创建的过程剖析

    http://blog.csdn.net/wangyin159/article/details/47082125 在Linux环境下,pthread库提供的pthread_create()API函数, ...

  2. Nginx 的线程池与性能剖析

    http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt158   正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方 ...

  3. Android多线程研究(1)——线程基础及源代码剖析

    从今天起我们来看一下Android中的多线程的知识,Android入门easy,可是要完毕一个完好的产品却不easy,让我们从线程開始一步步深入Android内部. 一.线程基础回想 package ...

  4. pthread_create线程创建的过程剖析(转)

    概述 在Linux环境下,pthread库提供的pthread_create()API函数,用于创建一个线程.线程创建失败时,它可能会返回ENOMEM或EAGAIN.这篇文章主要讨论线程创建过程中碰到 ...

  5. Java线程池核心原理剖析

    在系统开发时,我们经常会遇到“池”的概念.使用池一种以空间换时间的做法,通常在内存中事先保存一系列整装待命的对象,以供后期供其他对象随时调用.常见的池有:数据库连接池,socket连接池,线程池等.今 ...

  6. Nginx 的线程池与性能剖析【转载】

    正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为此,NGIN ...

  7. Netty源码分析第2章(NioEventLoop)---->第4节: NioEventLoop线程的启动

    Netty源码分析第二章: NioEventLoop   第四节: NioEventLoop线程的启动 之前的小节我们学习了NioEventLoop的创建以及线程分配器的初始化, 那么NioEvent ...

  8. 循序渐进 Jprofiler

    一 Jprofiler 1 什么是Jprofiler JProfiler是一个全功能的Java剖析工具(profiler),专用于分析J2SE和J2EE应用程式.它把CPU.线程和内存的剖析组合在一个 ...

  9. JProfiler使用入门(一)——准备工作

      JProfiler是一个全功能的Java剖析工具(profiler),主要用于检查和跟踪系统(限于Java开发的)的性能. JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收 ...

随机推荐

  1. ()centos6.8安装配置ftp服务器

    ftp传输原理 客户端通过某软件用某个端口(a端口)向服务端发起tcp连接请求,同时告诉服务端客户端另一个空闲端口号(b端口),服务端用21端口与客户端建立一条控制连接通道. 接着在默认情况下,服务端 ...

  2. 使用 Jmeter 做 Web 接口测试-详解

    接口测试概述 定义 WIKI定义:接口测试作为集成测 试的一部分,通过直接控制API来判断系统的功能性,可靠性,性能与安全性.API测试是没有界面的,执行在通讯 层.API 测试在自动化测试中有着重要 ...

  3. NOI模拟题1 Problem A: sub

    题面 Sample Input 5 7 2 -1 -3 1 1 1 2 1 3 3 4 3 5 2 1 3 0 2 1 2 1 2 1 1 -3 2 Sample Output 2 4 5 2 HIN ...

  4. git——简易指南

    Git对于我来说,只知道是一个版本控制器,类似于乌龟的svn.其中也仅仅会几个常的命令,比如说“更新git pull”.“提交git push”等等,因为记得当初使用的时候,师傅告诉我,对于你不懂这个 ...

  5. 【redis】redis实现API接口调用调用次数的限制

    redis实现API接口调用调用次数的限制 参考地址:https://bbs.csdn.net/topics/391856106?page=1 参考地址:https://www.cnblogs.com ...

  6. Cannot create JDBC driver of class '' for connect URL 'null'问题解决方法2

    1)启动Tomcat服务器,打开浏览器,输入http://localhost:8080/admin(其中localhost是名称服务器或称为主机),进入管理界面的登陆页面,这时候请输入原来安装时要求输 ...

  7. 【2048小游戏】——CSS/原生js爬坑之纯CSS模态对话框&游戏结束

    引言:2048小游戏的结束界面,使用纯CSS制作模态对话框,一般做模态对话框都会使用BootStrap自带的模态对话框组件方便使用,但在制作要运行在移动端的小项目时,就不能使用BootStrap,因为 ...

  8. Spring3和Quartz2的应用实例

    /** * 任务调度类 * @author Joyce.Luo * @date 2015-3-31 下午03:32:04 * @version V3.0 * @since Tomcat6.0,Jdk1 ...

  9. 点击页面li显示li中文字

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  10. void f(int(&amp;p)[3]){} 和void f(int(*p)[3]){}的差别

    #include<iostream> using namespace std; void f(int(&p)[3]){          cout<<p[0]<& ...