线程(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 899 A.Splitting in Teams
A. Splitting in Teams time limit per test 1 second memory limit per test 256 megabytes input sta ...
- 微信公众号开发C#系列-12、微信前端开发利器:WeUI
1.前言 通过前面系列文章的学习与讲解,相信大家已经对微信的开发有了一个全新的认识.后端基本能够基于盛派的第三方sdk搞定大部分事宜,剩下的就是前端了.关于手机端的浏览器的兼容性问题相信一直是开发者们 ...
- luogu P3376 【模板】网络最大流(no)ek
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- iOS7开发技巧
和任何新的iOS版本一样,有着一堆堆的新技巧和修改需要处理.有些我并不会立即遇到,所以这篇文章并不是一套完整技巧汇总.只是分享一些我碰巧遇到的问题. 如果你有任何更多的发现,可以发Twitter或者e ...
- 安卓Webview缓存网页数据(无网络正常显示)
热度 1已有 52 次阅读2016-8-26 17:53 |个人分类:常见问题|系统分类:移动开发 一.需求经历 最近的项目是一个原生 +webview 显示的 APP,一开始的时候,网站那边要求我们 ...
- WinRAR4.20注册文件key文件注册码
1.首先安装rar4.2官方版 2.在WinRAR已安装文件夹内新建文本文档,打开文档,把下面代码复制进去 RAR registration datawncnUnlimited Company Lic ...
- Mac. 文件夹赋予权限
1. click on your background to go to finder click on go and go to folder /usr right click on local a ...
- 【音乐App】—— Vue-music 项目学习笔记:播放器内置组件开发(二)
前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 播放模式切换 歌词滚动显示 ...
- poj 3307 Smart Sister 打表解因子生成数问题
题意: 给i,求由仅以2,3,5,7为因子的数中第i个是多少. 分析: 打表. 代码: //poj 3307 //sep9 #include <iostream> using namesp ...
- 面试题:使用finalkeyword修饰一个变量时,是引用不能变,还是引用的对象不能变?
/* * 问题:使用finalkeyword修饰一个变量时,是引用不能变,还是引用的对象不能变 * 答: * 使用finalkeyword修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内 ...