银行取款[多线程]{使用同步代码块确保线程同步}

经典例子:老婆(朱丽叶)老公(罗密欧),使用银行卡和存折,或者网银等,同时对同一账户操作的安全问题。

此处用多线程实现,同时取款的模拟实现,使用同步代码块确保线程同步,查看取款安全隐患问题,代码如下:

--------------------------------------------------------------------------------------------------------------------------------------

 * 线程同步 :使用同步块,实现线程同步
 * 同步synchronized块的对象监视锁可为为: 任意的对象(此处为'account'对象)。
 * (Runnable适用于共享同一对象(如:this),如果Thread继承就会有问题[保证Thread继承下安全:1.锁使用涉及当前对象外的对象(例如:SyncBlock、BankAccount对象外的其他类对象;2.锁使用静态当前类对象)])
 * 多个线程使用同一把锁,如果线程安全必需确保:多个线程使用的是同一个对象监视锁对象
 * synchronized关键字修饰的语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
 * 所有访问此同步代码块的线程都在同步块外等待,都会判断同步锁,降低效率,但确保线程安全问题,外,同步代码块外代码正常执行
 * 同步方法优于同步代码块:性能和memory空间上。
 * 同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可

--------------------------------------------------------------------------------------------------------------------------------------
 private void makeWithdraw(int amount){
  /*.........同步代码块外代码.............*/
  synchronized (account) {
   //同步代码
  }
 }

银行账户:

package com.tsxs.bank;

public class BankAccount {
	//余额
	private int balance = 500;
	//查询
	public int getBalance(){
		return banlance;
	}
	//取款
	public void withdraw(int amount){
		banlance = banlance - amount;
	}
	//存款
	public void deposit(int amount){
		banlance = banlance + amount;
	}
}

 

同步代码块代码:

package com.tsxs.syncmethods;

import com.tsxs.bank.BankAccount;
/**
 * 此线程类实现Runnable接口<br />
 * 线程同步 :使用同步块,实现线程同步<br />
 * 同步synchronized块的对象监视锁可为为: 任意的对象(此处为'account'对象)。<br />
 * (Runnable适用于共享同一对象(如:this),如果Thread继承就会有问题[保证Thread继承下安全:1.锁使用涉及当前对象外的对象(例如:SyncBlock、BankAccount对象外的其他类对象;2.锁使用静态当前类对象)])<br />
 * 多个线程使用同一把锁,如果线程安全必需确保:多个线程使用的是同一个对象监视锁对象<br />
 * 所有访问此同步代码块的线程都在同步块外等待,都会判断同步锁,降低效率,但确保线程安全问题,外,同步代码块外代码正常执行<br />
 * 同步方法优于同步代码块:性能和memory空间上。
 * */
public class SyncBlock implements Runnable {
	//所有Thread多线程线程都共享Runnable(接口对象)和account对象
	private BankAccount account = new BankAccount();
	@Override
	public void run() {
		for(int i = 0; i< 5; i++){			//总共取款5次
			makeWithdraw(100);			//每次取款100
			if(account.getBalance() < 0){
				System.out.println(""+Thread.currentThread().getName()+"   透支了!");
			}
		}
	}

	/**
	 * makeWithdraw 账户取款
	 * @param amount 取款金额<br />
	 * 打印log记录取款过程
	 * */
	private void makeWithdraw(int amount){
		/*.........同步代码块外代码.............*/
		synchronized (account) {
			if(account.getBalance() >= amount){			//如果余额足够则取款
				System.out.println(""+Thread.currentThread().getName()+"   准备取款!");
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					System.out.println(Thread.currentThread().getName()+"   准备取款,等待0.5s线程中断!"+e.getMessage());
				}
				account.withdraw(amount);
				System.out.println(""+Thread.currentThread().getName()+"   完成"+amount+"取款!余额为"+account.getBalance());
			}else{			//余额不足则提示
				System.out.println(""+"余额不足以支付"+Thread.currentThread().getName()+amount+"   的取款,余额为"+account.getBalance());
			}
		}
	}
}

测试代码:

package com.tsxs.test;

import org.junit.Test;

import com.tsxs.syncmethods.NoSync;
import com.tsxs.syncmethods.SyncBlock;
import com.tsxs.syncmethods.SyncMethod;

public class TreadSyncTest {

//	@Test
//	public void test() {
/*Junit不适合多线程并发测试。
    因为线程还在激活状态的时候,Junit已经执行完成。
	在Junit的TestRunner中,它没有被设计成搜寻Runnable实例,
	并且等待这些线程发出报告,它只是执行它们并且忽略了它们的存在。
	综上,不可能在Junit中编写和维护多线程的单元测试。
}*/
	public static void main(String[] args) {
		//实现Runnable:所有Thread多线程线程都共享Runnable(接口对象)
//		NoSync target =new NoSync();
//		SyncMethod target = new SyncMethod();
		SyncBlock target = new SyncBlock();
		//创建李琦和他老婆两个线程实现取款(同时)
		Thread lq = new Thread(target);
		lq.setName("罗密欧");
		Thread lqwf = new Thread(target);
		lqwf.setName("朱丽叶");
		//调用Thread对象的start()方法,启动线程,执行run()方法(OS)
		lq.start();
		lqwf.start();
	}
}

测试结果:

朱丽叶   准备取款!
朱丽叶   完成100取款!余额为400
朱丽叶   准备取款!
朱丽叶   完成100取款!余额为300
朱丽叶   准备取款!
朱丽叶   完成100取款!余额为200
罗密欧   准备取款!
罗密欧   完成100取款!余额为100
罗密欧   准备取款!
罗密欧   完成100取款!余额为0
余额不足以支付罗密欧100   的取款,余额为0
余额不足以支付罗密欧100   的取款,余额为0
余额不足以支付罗密欧100   的取款,余额为0
余额不足以支付朱丽叶100   的取款,余额为0
余额不足以支付朱丽叶100   的取款,余额为0

分析结果:

双线程总共取款10次,账户总额为500.

取款结果:在多线程访问下,成功取款总额为500,并且其他取款下,正确提示信息。

多线程访问安全保证!

时间: 2024-09-20 00:32:24

银行取款[多线程]{使用同步代码块确保线程同步}的相关文章

银行取款[多线程]{使用重入锁Lock接口ReentrantLock锁确保线程同步}

经典例子:老婆(朱丽叶)老公(罗密欧),使用银行卡和存折,或者网银等,同时对同一账户操作的安全问题.  此处用多线程实现,同时取款的模拟实现,使用使用Lock接口ReentrantLock锁确保线程同步,查看取款安全隐患问题,代码如下: -----------------------------------------------------------------------------------------------------------------------------------

银行取款[多线程]{使用同步方法确保线程同步}

  经典例子:老婆(朱丽叶)老公(罗密欧),使用银行卡和存折,或者网银等,同时对同一账户操作的安全问题.  此处用多线程实现,同时取款的模拟实现,使用同步方法确保线程同步,查看取款安全隐患问题,代码如下: -------------------------------------------------------------------------------------------------------------------------------------------  * 线程同步

银行取款[多线程]{未进行线程同步}(junit不适合多线程并发单元测试)

        由于计算机多任务.多进程.多线程的支持,使得计算机资源的服务效率提高,服务器对请求的也使用线程来相应,所有,代码中涉及到同时对共享数据的操作,将在 多线程环境中操作数据,导致数据安全问题.      经典例子:老婆(朱丽叶)老公(罗密欧),使用银行卡和存折,或者网银等,同时对同一账户操作的安全问题.      如果要保证多线程下数据安全,就要实现线程同步(例如:一间小厕所,就得有一个锁,保证同一时间为一个人服务).其他文章讲: 此处用多线程实现,同时取款的模拟实现,未进行线程同步

JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程)把票陆陆续续的卖完了之后,我们要反思一下,这里面有没有安全隐患呢?在实际情况中,这种事情我们是必须要去考虑安全问题的,那我们模拟一下错误 package com.lgl.hellojava; import javax.security.auth.callback.TextInputCallback

线程-同步代码块的问题。。。。。

问题描述 同步代码块的问题..... 数据库的几张表常用表的数据,我想写到几个静态变量中. 然后提供若干个get方法,同时还有一个set方法重置所有的静态变量. 请问如何能够在set重置方法没完成以前,让get方法的线程等待? 同时几个get方法又不能有相互影响. 就是set没完成,所有的get需要等待,但是不同的get之间没完成不需要等待. 来人啊... 解决方案 http://my.oschina.net/tinglanrmb32/blog/339661 解决方案二: http://blog

基本线程同步(五)使用Lock同步代码块

声明:本文是< Java 7 Concurrency Cookbook >的第二章,作者: Javier Fernández González     译者:许巧辉 校对:方腾飞 使用Lock同步代码块 Java提供另外的机制用来同步代码块.它比synchronized关键字更加强大.灵活.它是基于Lock接口和实现它的类(如ReentrantLock).这种机制有如下优势: 它允许以一种更灵活的方式来构建synchronized块.使用synchronized关键字,你必须以结构化方式得到释

JAVA里synchronized同步代码块的一点疑问

问题描述 代码如下:public class SomeObj { public void print(int i){ System.out.println(Thread.currentThread().getName()+DateHelper.getNow()+ " " + i); try { wait(1000); } catch (InterruptedException e) { e.printStackTrace(); } }}public class ThreadA exte

java线程学习4——线程同步之同步代码块

  模拟一个场景,两个人对同一个账户同时取钱   package cn.xy.Thread; public class Account {  /**   * 账户号   */  private String accountNo;  /**   * 账户余额   */  private double balance;  public Account()  {   super();  }  public Account(String accountNo, double balance)  {   s

银行取款[多线程]{使用volatile修饰共享变量,但此场景并不保证线程同步}

经典例子:老婆(朱丽叶)老公(罗密欧),使用银行卡和存折,或者网银等,同时对同一账户操作的安全问题. 此处用多线程实现,同时取款的模拟实现,使用volatile修饰共享变量,但此场景并不保证线程同步,查看取款安全隐患问题,代码如下: 我学习地址(Thanks for auther): Java 理论与实践: 正确使用 Volatile 变量 java中volatile关键字的含义 ----------------------------------------------------------