线程(while 和 if 剖析)

那存钱取钱为例:

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

  如果只有存钱和取钱各自只有一个线程在操作使用 if 的话可以满足要求:

  

 1 package com.thread;
 2 /**
 3  * 模拟同步取款的问题
 4  * @author dr
 5  *
 6  */
 7 public class ThreadTest {
 8     public static void main(String[] args) {
 9         final Account account = new Account();
10         //取出200
11         new Thread(new Runnable() {
12             @Override
13             public void run() {
14                 for(int i=0;i<3;i++){
15                     try {
16                         Thread.sleep(500);
17                     } catch (InterruptedException e) {
18                         // TODO Auto-generated catch block
19                         e.printStackTrace();
20                     }
21                     account.getMoney(200);
22                 }
23             }
24         }).start();
25         //存入300
26         new Thread(new Runnable() {
27             @Override
28             public void run() {
29                 for(int i=0;i<3;i++){
30                     try {
31                         Thread.sleep(500);
32                     } catch (InterruptedException e) {
33                         // TODO Auto-generated catch block
34                         e.printStackTrace();
35                     }
36                     account.setMoney(300);
37                 }
38             }
39         }).start();
40     }
41 }
42 class Account {
43
44     private int balance = 1000;
45     private boolean setMoney = true;
46     public synchronized void getMoney(int count){
47         if(setMoney){
48             try {
49                 this.wait();
50             } catch (InterruptedException e) {
51                 // TODO Auto-generated catch block
52                 e.printStackTrace();
53             }
54         }
55         int result =balance - count;
56         if(result >= 0){
57             balance = result;
58             System.out.println(Thread.currentThread().getName()+"取出:"+count+"元,剩余:"+balance);
59         }else{
60             System.out.println("余额不足...");
61         }
62         setMoney = true;
63         this.notify();
64     }
65     public synchronized void setMoney(int count){
66             if(!setMoney){
67                 try {
68                     this.wait();
69                 } catch (InterruptedException e) {
70                     // TODO Auto-generated catch block
71                     e.printStackTrace();
72                 }
73             }
74             balance += count;
75             System.out.println(Thread.currentThread().getName()+"存入:"+count+"元,剩余:"+balance);
76             setMoney =  false;
77             this.notify();
78     }
79
80 }

  但是如果存钱和取钱包含多个线程的话 if 就不行 只有使用while才能满足条件

 1 package com.thread;
 2 /**
 3  * 模拟同步取款的问题
 4  * @author dr
 5  *
 6  */
 7 public class ThreadTest {
 8     public static void main(String[] args) {
 9         final Account account = new Account();
10         //取出200 两个取钱的线程
11         for(int i=0;i<2;i++){
12             new Thread(new Runnable() {
13                 @Override
14                 public void run() {
15                     for(int i=0;i<3;i++){
16                         try {
17                             Thread.sleep(500);
18                         } catch (InterruptedException e) {
19                             // TODO Auto-generated catch block
20                             e.printStackTrace();
21                         }
22                         account.getMoney(200);
23                     }
24                 }
25             }).start();
26         }
27         //存入300 两个存钱的线程
28         for(int i=0;i<2;i++){
29             new Thread(new Runnable() {
30                 @Override
31                 public void run() {
32                     for(int i=0;i<3;i++){
33                         try {
34                             Thread.sleep(500);
35                         } catch (InterruptedException e) {
36                             // TODO Auto-generated catch block
37                             e.printStackTrace();
38                         }
39                         account.setMoney(300);
40                     }
41                 }
42             }).start();
43         }
44     }
45 }
46 class Account {
47
48     private int balance = 1000;
49     //先存钱
50     private boolean setMoney = true;
51     public synchronized void getMoney(int count){
52         while(setMoney){
53             try {
54                 this.wait();
55             } catch (InterruptedException e) {
56                 // TODO Auto-generated catch block
57                 e.printStackTrace();
58             }
59         }
60         int result =balance - count;
61         if(result >= 0){
62             balance = result;
63             System.out.println(Thread.currentThread().getName()+"取出:"+count+"元,剩余:"+balance);
64         }else{
65             System.out.println("余额不足...");
66         }
67         setMoney = true;
68         this.notifyAll();
69     }
70     public synchronized void setMoney(int count){
71             while(!setMoney){
72                 try {
73                     this.wait();
74                 } catch (InterruptedException e) {
75                     // TODO Auto-generated catch block
76                     e.printStackTrace();
77                 }
78             }
79             balance += count;
80             System.out.println(Thread.currentThread().getName()+"存入:"+count+"元,剩余:"+balance);
81             setMoney =  false;
82             this.notifyAll();
83     }
84
85 }

分析:
  有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 否则会出现全部等待状态

时间: 2024-10-14 01:51:17

线程(while 和 if 剖析)的相关文章

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

从今天起我们来看一下Android中的多线程的知识,Android入门easy,可是要完毕一个完好的产品却不easy,让我们从线程開始一步步深入Android内部. 一.线程基础回想 package com.maso.test; public class TraditionalThread { public static void main(String[] args) { /* * 线程的第一种创建方式 */ Thread thread1 = new Thread(){ @Override p

Nginx 的线程池与性能剖析

http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt158 正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为此,NGINX工作在非阻塞的socket模式下,并使用了epoll 和 kqueue这样有效的方法. 因为满负载进程的数量很少(通常每核CPU只有一个)而且恒定,所以任务切换只消耗很少的内

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

正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为此,NGINX工作在非阻塞的socket模式下,并使用了epoll 和 kqueue这样有效的方法. 因为满负载进程的数量很少(通常每核CPU只有一个)而且恒定,所以任务切换只消耗很少的内存,而且不会浪费CPU周期.通过NGINX本身的实例,这种方法的优点已经为众人所知.NGINX可以非常好地处理百万级规模的并

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

概述 在Linux环境下,pthread库提供的pthread_create()API函数,用于创建一个线程.线程创建失败时,它可能会返回ENOMEM或EAGAIN.这篇文章主要讨论线程创建过程中碰到的一些问题和解决方法. 创建线程 首先,本文用的实例代码example.c: /* example.c*/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h&g

pthread_create线程创建的过程剖析

http://blog.csdn.net/wangyin159/article/details/47082125 在Linux环境下,pthread库提供的pthread_create()API函数,用于创建一个线程.线程创建失败时,它可能会返回ENOMEM或EAGAIN.这篇文章主要讨论线程创建过程中碰到的一些问题和解决方法. 创建线程 首先,本文用的实例代码example.c: /* example.c*/#include <stdio.h>#include <stdlib.h>

Concurrent包总结——线程任务执行框架

一 Executor接口 Executor接口的对象是一种执行任务的方式.它能够使提交的任务和执行任务的线程的管理解耦.我们通常用Executor来代替new一个Thread对象来执行任务.这样可以省略底层线程的管理细节. 例如: executor.excute(new RunnableTask()); concurrent包中提供了比较常用的Executor的实现,这些实现类都实现了一个更加灵活的类ExecutorService.而ThreadPoolExecutor则提供了一个可扩展的线程池

面向Web Cloud的HTML5 App开发实战:Browser&amp;HTML5&amp;CSS3&amp;PhoneGap&amp;jQuery Mobile&amp; WebSocket&amp;Node.js(2天)

如何理解Android架构设计的初心并开发出搭载Android系统并且具备深度定制和软硬整合能力特色产品,是本课程解决的问题. 课程以Android的五大核心:HAL.Binder.Native Service.Android Service(并以AMS和WMS为例).View System为主轴,一次性彻底掌握Android的精髓. 之所以是开发Android产品的必修课,缘起于: 1,     HAL是Android Framework&Application与底层硬件整合的关键技术和必修技

Android架构设计和软硬整合完整训练:HAL&amp;Framework&amp;Native Service&amp;Android Service&amp;Best Practice

如何理解Android架构设计的初心并开发出搭载Android系统并且具备深度定制和软硬整合能力特色产品,是本课程解决的问题. 课程以Android的五大核心:HAL.Binder.Native Service.Android Service(并以AMS和WMS为例).View System为主轴,一次性彻底掌握Android的精髓. 之所以是开发Android产品的必修课,缘起于: 1, HAL是Android Framework&Application与底层硬件整合的关键技术和必修技术: 2

Android架构设计和软硬整合:HAL&amp;Framework&amp;Native Service&amp;Android Service&amp;Best Practice

如何理解Android架构设计的初心并开发出搭载Android系统并且具备深度定制和软硬整合能力特色产品,是本课程解决的问题. 课程以Android的五大核心:HAL.Binder.Native Service.Android Service(并以AMS和WMS为例).View System为主轴,一次性彻底掌握Android的精髓. 之所以是开发Android产品的必修课,缘起于: 1, HAL是Android Framework&Application与底层硬件整合的关键技术和必修技术: 2