以银行取钱为例模拟Java多线程同步问题完整代码

简单了解下在操作系统中进程和线程的区别:

  进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)

  线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)

  线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。

  多进程是指操作系统能同时运行多个任务(程序)。

  多线程是指在同一程序中有多个顺序流在执行。首先存钱取钱的这个操作,应该是线程操作的,可以有很多的顾客,这意思就是得有多个线程,多个线程之间共同操作一个银行,银行的金额就需要同步。才能保证线程安全。

所以,下面就把这个代码的实例放这,有不对的地方,还请指出来哈。因为有个老铁问这个多线程的代码。

首先是银行,这个对象model的创建。

package com.lxk.threadTest.bank;
/**
 * 银行model,一个总金额属性。
 * <p>
 *
 * @author lxk on 2017/6/26
 */
public class Bank {
	/**
   * 给银行个启动资金,不然怎么干生意呢。
   */
	private int sum = 200;
	//这个从来不这么用,但也算是正确的一种加锁的机制:同步代码块。
	//Object obj = new Object();
	/**
   * 存钱
   * 要是不加[synchronized--同步函数],则会出现多线程安全问题。
   */
	public synchronized void add(int n) {
		//synchronized (obj) {
		sum = sum + n;
		try {
			Thread.sleep(10);
		}
		catch (Exception ignore) {
		}
		//当存钱次数变多的时候,就可以发现,存钱的线程确实是2个在交替执行存钱这个动作的。
		System.out.println(Thread.currentThread().getName() + "...sum=" + sum);
		//}
	}
	/**
   * 取钱
   * 要是不加[synchronized--同步函数],则会出现多线程安全问题。
   */
	public synchronized void reduce(int n) {
		if (sum - n >= 0) {
			sum = sum - n;
		} else {
			System.out.println("bank's money is not enough !");
		}
		try {
			Thread.sleep(30);
		}
		catch (Exception ignore) {
		}
		//当存钱次数变多的时候,就可以发现,存钱的线程确实是2个在交替执行存钱这个动作的。
		System.out.println(Thread.currentThread().getName() + "...sum=" + sum);
	}
}

在代码里面有存和取2个方法,这2个方法,以及一个总金额,里面有部分被注释掉的代码,那个是简单易懂好理解的,多线程加锁互斥,保证线程间同步的方法。

但是这个是不常用的方法,常用的就是使用synchronized这个关键字来修饰同步方法。

客户对象的model

package com.lxk.threadTest.bank;
/**
 * 顾客,实现runnable()接口,多个人可以一起存钱
 *
 * @author lxk on 2017/6/26
 */
public class Customer implements Runnable {
	/**
   * 存钱类型
   */
	static final String TYPE_ADD = "add";
	/**
   * 取钱类型
   */
	static final String TYPE_REDUCE = "reduce";
	/**
   * 银行
   */
	private Bank bank;
	/**
   * 对钱的操作类型,存钱or取钱
   */
	private String type;
	/**
   * 操作的次数,理论上是个正数
   */
	private int time;
	/**
   * 要存或者取多少钱
   */
	private int money;
	public Customer() {
	}
	public Customer(Bank bank, String type, int time, int money) {
		this.bank = bank;
		this.type = type;
		this.time = time;
		this.money = money;
	}
	@Override
	  public void run() {
		for (int x = 0; x < time; x++) {
			if (TYPE_ADD.equals(type)) {
				bank.add(money);
			} else if (TYPE_REDUCE.equals(type)) {
				bank.reduce(money);
			}
		}
	}
}

客户对象,因为可以很多个客户同时访问一个银行,所以,这个存钱取钱的操作就用线程来实现。

属性就构造方法传值了。

main方法

package com.lxk.threadTest.bank;
/**
 * 银行存钱的多线程实例
 * <p>
 * 【需求:】
 * 银行有一个金库。
 * 有两个储户分别存或者取n * 100。
 * 目的:该程序是否有安全问题,如果有,如何解决?
 * <p>
 * 【如何找问题:】
 * 1,明确哪些代码是多线程运行代码。
 * 2,明确共享数据。
 * 3,明确多线程运行代码中哪些语句是操作共享数据的。
 *
 * @author lxk on 2017/6/26
 */
public class Main {
	public static void main(String[] args) {
		//一个银行and多个客户
		Bank bank = new Bank();
		int time = 10000;
		int money = 100;
		//这个客户存钱
		Customer c1 = new Customer(bank, Customer.TYPE_ADD, time, money);
		//这个客户取钱
		Customer c2 = new Customer(bank, Customer.TYPE_REDUCE, time, money);
		Thread t1 = new Thread(c1);
		Thread t2 = new Thread(c2);
		t1.start();
		t2.start();
	}
}

上述代码实际运行效果如下图。

这个存取钱的次数要是小了,就可能会看到2个线程有先后顺序,所以,这个次数咱整多点,然后,就看到如图所示的情况,线程1是取钱的,线程0时存钱的,可以看到2个线程是互相交错执行的,有存有取,没有规律可言。

这个就保证了数据的同步了。

至于如何才能不同步,也就是异常的现象,

你可以把add方法的这个synchronized关键字去掉之后,把次数调小一点改成3次,sum的初始值给设置成0.你再试试代码,

就会发现所谓的不同步现象。

上图的右边就是不同步的结果,2个人每次存100,存三次,总数是不是得,100,200,300,400,500,600.得长。

但是,运行结果却不是的,

这个时候,你再把synchronized给add方法加上去,就会出现左边的图的结果,这个就是正确的结果。

我是为了,有存有取,所以,就又加了个方法。代码就变成上面的样子啦。

差不多都是线程间同步的例子啦。

我就简单记录下代码。用的时候,可以分分钟就拿出来。

总结

以上就是本文关于以银行取钱为例模拟Java多线程同步问题完整代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

java多线程编程实例

Java多线程定时器Timer原理及实现

Java通过卖票理解多线程

如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

(0)

相关推荐

  • Java多线程中断机制三种方法及示例

    概述 之前讲解Thread类中方法的时候,interrupt().interrupted().isInterrupted()三个方法没有讲得很清楚,只是提了一下.现在把这三个方法同一放到这里来讲,因为这三个方法都涉及到多线程的一个知识点----中断机制. Java没有提供一种安全.直接的方法来停止某个线程,而是提供了中断机制.中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理.有个例子举个蛮好,就像父母叮嘱出门在外的子女要注意身体一样,父母说了,但是子女

  • Java多线程之显示锁和内置锁总结详解

    总结多线程之显示锁和内置锁 Java中具有通过Synchronized实现的内置锁,和ReentrantLock实现的显示锁,这两种锁各有各的好处,算是互有补充,这篇文章就是做一个总结. *Synchronized* 内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁. synchronized(list){ //获得锁 list.append(); list.count(); }//释放锁 通信 与Synchronized配套使用的通信方法通常

  • Java多线程Atomic包操作原子变量与原子类详解

    在阅读这篇文章之前,大家可以先看下<Java多线程atomic包介绍及使用方法>,了解atomic包的相关内容. 一.何谓Atomic? Atomic一词跟原子有点关系,后者曾被人认为是最小物质的单位.计算机中的Atomic是指不能分割成若干部分的意思.如果一段代码被认为是Atomic,则表示这段代码在执行过程中,是不能被中断的.通常来说,原子指令由硬件提供,供软件来实现原子方法(某个线程进入该方法后,就不会被中断,直到其执行完成) 在x86平台上,CPU提供了在指令执行期间对总线加锁的手段.

  • Java多线程中不同条件下编写生产消费者模型方法介绍

    简介: 生产者.消费者模型是多线程编程的常见问题,最简单的一个生产者.一个消费者线程模型大多数人都能够写出来,但是一旦条件发生变化,我们就很容易掉进多线程的bug中.这篇文章主要讲解了生产者和消费者的数量,商品缓存位置数量,商品数量等多个条件的不同组合下,写出正确的生产者消费者模型的方法. 欢迎探讨,如有错误敬请指正 生产消费者模型 生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品.生产消费者模式

  • java多线程之线程,进程和Synchronized概念初解

    一.进程与线程的概念 (1)在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单位都是进程. 在未配置 OS 的系统中,程序的执行方式是顺序执行,即必须在一个程序执行完后,才允许另一个程序执行:在多道程序环境下,则允许多个程序并发执行.程序的这两种执行方式间有着显著的不同.也正是程序并发执行时的这种特征,才导致了在操作系统中引入进程的概念. 自从在 20 世纪 60 年代人们提出了进程的概念后,在 OS 中一直都是以进程作为能拥有资源和独立运行的基本单位的.直到 20 世纪 8

  • Java多线程中ReentrantLock与Condition详解

    一.ReentrantLock类 1.1什么是reentrantlock java.util.concurrent.lock中的Lock框架是锁定的一个抽象,它允许把锁定的实现作为Java类,而不是作为语言的特性来实现.这就为Lock的多种实现留下了空间,各种实现可能有不同的调度算法.性能特性或者锁定语义.ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,但是添加了类似锁投票.定时锁等候和可中断锁等候的一些特性.此外,它还提供了在激烈争用情况下更

  • Java多线程定时器Timer原理及实现

    前言 定时/计划功能在Java应用的各个领域都使用得非常多,比方说Web层面,可能一个项目要定时采集话单.定时更新某些缓存.定时清理一批不活跃用户等等.定时计划任务功能在Java中主要使用的就是Timer对象,它在内部使用多线程方式进行处理,所以它和多线程技术关联还是相当大的.那和ThreadLocal一样,还是先讲原理再讲使用,Timer的实现原理不难,就简单扫一下就好了. Timer的schedule(TimeTask task, Date time)的使用 该方法的作用是在执行的日期执行一

  • Java多线程窗口售票问题实例

    本文介绍了多线程实现多个窗口售票问题的两种枷锁方式, 分别是synchronized 和lock()和unlock() 具体代码如下: 第一种: package Runnable; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* * 同步 * 这里有两种方式加锁 * 分别是 * 1.synchronized * 2.lock()和unlock() */ publ

  • 以银行取钱为例模拟Java多线程同步问题完整代码

    简单了解下在操作系统中进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小.(线程是cpu调度的最小单位) 线程和进程一样分为五个阶段:创建.就绪.运行.阻塞.终止. 多进程是指操作系统能同时运行多个任务(程序). 多线程是指在同一程序中有多个顺序流在执行.首先存钱取钱的这个操作,应该是线程操作的

  • Java使用锁解决银行取钱问题实例分析

    本文实例讲述了Java使用锁解决银行取钱问题.分享给大家供大家参考,具体如下: 一 点睛 1 释放同步监视器 线程会在如下几种情况下释放对同步监视器的锁定: 当前线程的同步方法.同步代码块执行结束,当前线程即释放同步监视器. 当线程在同步代码块.同步方法中遇到break.return终止了该代码块.该方法的继续执行,当前线程将会释放同步监视器. 当线程在同步代码块.同步方法中出现了未处理的Error或Exception,导致了该代码块.该方法异常结束时将会释放同步监视器. 当线程执行同步代码块或

  • Java同步代码块解决银行取钱的安全问题实例分析

    本文实例讲述了Java同步代码块解决银行取钱的安全问题.分享给大家供大家参考,具体如下: 一 点睛 为了解决类似银行取钱这类安全问题,Java的多线程支持引入了同步监视器来解决这个问题,使用同步监视器的通用方法是同步代码块.同步代码块的语法格式是: synchronized(obj) { //此处代码块就是同步代码块. } 上面语法格式中种的obj就是同步监视器,上面代码的含义是:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定. 任何时刻只能由一个线程获得对同步监视器的锁定,当同步代码

  • Java使用同步方法解决银行取钱的安全问题案例分析

    本文实例讲述了Java使用同步方法解决银行取钱的安全问题.分享给大家供大家参考,具体如下: 一 点睛 与同步代码块对应,Java的多线程安全支持还提供了同步方法,同步方法就是使用synchronized关键字来修饰某个方法,则该方法称为同步方法.对于synchronized修饰的实例方法(非static方法)而言,无须显示指定同步监视器,同步方法的同步监视器是this,也就是调用该方法的对象. 通过使用同步方法可以非常方便地实现线程安全的类,线程安全的类具有如下特征. 该类的对象可以被多个线程安

  • Java银行取钱线程安全问题实例分析

    本文实例讲述了Java银行取钱线程安全问题.分享给大家供大家参考,具体如下: 一 定义一个账户类 public class Account { // 封装账户编号.账户余额的两个成员变量 private String accountNo; private double balance; public Account(){} // 构造器 public Account(String accountNo , double balance) { this.accountNo = accountNo;

  • 使用javascript函数编写简单银行取钱存钱流程

    具体代码如下所述: const readline = require('readline-sync')//引用readline-sync let arr = [['zhang', '123', 2000], ['yang', '123456', 3000]]; //登陆 let add = function () { let s = 2;//输入错误的次数 while (true) { console.log('请输入用户名:'); let user = readline.question();

  • 五种Java多线程同步的方法

    为什么要线程同步 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常.举 个例子,如果一个银行账户同时被两个线程操作,一个取100块,一个存钱100块.假设账户原本有0块,如果取钱线程和存钱线程同时发生,会出现什么结果 呢?取钱不成功,账户余额是100.取钱成功了,账户余额是0.那到底是哪个呢?很难说清楚.因此多线程同步就是要解决这个问题. 一.不同步时的代码 Bank.java package threadTe

  • java多线程的同步方法实例代码

    java多线程的同步方法实例代码 先看一个段有关银行存钱的代码: class Bank { private int sum; public void add(int num){ sum = sum + num; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("total num is : " + sum); } } class Cu

  • 浅谈Java多线程的优点及代码示例

    尽管面临很多挑战,多线程有一些优点使得它一直被使用.这些优点是: 资源利用率更好 程序设计在某些情况下更简单 程序响应更快 资源利用率更好 想象一下,一个应用程序需要从本地文件系统中读取和处理文件的情景.比方说,从磁盘读取一个文件需要5秒,处理一个文件需要2秒.处理两个文件则需要: 5秒读取文件A 2秒处理文件A 5秒读取文件B 2秒处理文件B --------------------- 总共需要14秒 从磁盘中读取文件的时候,大部分的CPU时间用于等待磁盘去读取数据.在这段时间里,CPU非常的

  • java多线程-同步块实例讲解

    java多线程-同步块 Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java 同步块用来避免竞争.本文介绍以下内容: Java 同步关键字(synchronzied) 实例方法同步 静态方法同步 实例方法中同步块 静态方法中同步块 Java 同步示例 Java 同步关键字(synchronized) Java 中的同步块用 synchronized 标记.同步块在 Java 中是同步在某个对象上.所有同步在一个对象上的同步块在同时只能被一个线程进入并执

随机推荐