那存钱取钱为例:

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

  如果只有存钱和取钱各自只有一个线程在操作使用 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. Wordpress笔记:背景音乐

    想要在blog首页加上自动播放的背景音乐,能找到的插件与方法基本上都是讲在文章里添加的.侧边栏里添加文本的方法也总有美观等等这样那样的问题,折腾了几种之后终于搞定了.用的是Audio player插件 ...

  2. HDU——最大连续子序列(区间DP)

    上一个题的加强版! 最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  3. 关于bug的沟通

    关于BUG的沟通 一个人要去做一件事情,一般来说是按照自己的意愿去做的,如果不是自己想做而是被要求这么做的话,心里一定会留下点不愉快,特别是那种有自信有自己主见的人,比如说开发人员,当测试人员发现一个 ...

  4. BZOJ 3672 NOI 2014 购票

    题面 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市 ...

  5. 【spring cloud】对接口调用者提供API使用的安全验证微服务【这里仅通过代码展示一种设计思想】【后续可以加入redis限流的功能,某段时间某个IP可以访问API几次】

    场景: 公司的微服务集群,有些API 会对外提供接口,供其他厂商进行调用.这些公开的API接口,由一个OpenAPI微服务统一提供给大家. 那么所有的调用者在调用公开API接口的时候,需要验证是否有权 ...

  6. Python模拟浏览器上传文件脚本(Multipart/form-data格式)

    http协议本身的原始方法不支持multipart/form-data请求,这个请求由原始方法演变而来的. multipart/form-data的基础方法是post,也就是说是由post方法来组合实 ...

  7. 【温故知新】——CSS黑魔法小技巧可以少些不必要的js

    前言:这篇文章是转载[前端开发博客]的一篇技术文章,并非本人所写.只是个人觉得很实用,所以分享给大家.原文链接:github.com 1.利用 CSS 的 content 属性 attr 抓取资料需求 ...

  8. 【React Native开发】React Native移植原生Android项目(4)

    ),React Native技术交流4群(458982758),请不要反复加群!欢迎各位大牛,React Native技术爱好者加入交流!同一时候博客左側欢迎微信扫描关注订阅号,移动技术干货,精彩文章 ...

  9. Ajax学习(一)——与Ajax的初次相识

        AJAX是"Asynchronous Javascript And XML"的缩写,从字面上解释是"异步JavaScript和XML"的简称. 它不是一 ...

  10. GUID概念

     GUID概念 GUID: 即Globally Unique Identifier(全球唯一标识符) 也称作 UUID(Universally Unique IDentifier) . GUID是 ...