老生常谈的一个问题,就bank的那个例子,同一张卡同时取钱,并发2个,每一个取800,但卡里只有1000,不能让2我的同时操做.这里就须要线程同步.好比下面的DEMO. java
首先定义一个帐户类: 编程
package org.credo.thread.tongbu; public class Account { private String account; private double money; public Account(String account,double money){ this.account=account; this.money=money; } //根据account重写hashcode和equals方法. public int hasCode(){ return account.hashCode(); } public boolean equals(Object obj){ if(this==obj){ return true; } if(obj!=null && obj.getClass()==Account.class){ Account target=(Account)obj; return target.getAccount().equals(account); } return false; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } }再就是业务类:
package org.credo.thread.tongbu; public class Draw extends Thread{ private Account account; private double hopeGetMoney; public Draw(String name,Account account,double hopeGetMoney){ super(name); this.account=account; this.hopeGetMoney=hopeGetMoney; } //当多个线程修改同一个共享数据的时候,将会引起数据问题. public void run(){ if(account.getMoney() >= hopeGetMoney){ System.out.println(account.getAccount()+"---"+getName()+"取钱成功,取出金额为:"+hopeGetMoney); try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } //修改金额 account.setMoney(account.getMoney()-hopeGetMoney); System.out.println("余额为:"+account.getMoney()); }else{ System.out.println("余额不足,取款失败!"); } } }测试类:
package org.credo.thread.tongbu; public class NoSynchronizedTest { public static void main(String[] args) { //create a new account Account account=new Account("印度人", 1000); new Draw("印度人A", account, 800).start(); new Draw("印度人B", account, 800).start(); } }结果是:
印度人---印度人B取钱成功,取出金额为:800.0
印度人---印度人A取钱成功,取出金额为:800.0
余额为:200.0
余额为:-600.0 安全
天然是错的,毕竟这不是信用卡. 多线程
在这种场景下,account这个帐户必然要是必定时间内只能一我的操做的,是须要线程的同步的. 并发
以下code:在业务类的run方法总加入synchronized代码块. 工具
public void run(){ //使用account做为同步监视器,任何线程进入下面同步代码块以前必须先得到对account帐户的锁定. //其余线程没法得到锁,也就没法修改 //这种作法符合, 加锁---修改---释放锁 的逻辑. synchronized (account) { if(account.getMoney() >= hopeGetMoney){ System.out.println(account.getAccount()+"---"+getName()+"取钱成功,取出金额为:"+hopeGetMoney); try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } //修改金额 account.setMoney(account.getMoney()-hopeGetMoney); System.out.println("余额为:"+account.getMoney()); }else{ System.out.println("余额不足,取款失败!"); } } //结束,释放同步锁. }印度人---印度人A取钱成功,取出金额为:800.0
synchronized(obj){
//此处代码就是同步代码块
} 性能
与同步代码块对应的,java的多线程的安全支持还提供了同步方法,同步方法就是使用synchronized关键字去修饰某个方法.对于同步方法而言,其同步监视器就是this,就是该对象自己. 测试
用过使用同步方法能够很方便的实现线程安全的类,线程安全的类具备以下特征: ui
synchronized关键字能够修饰方法,代码块,但不能修改构造器,属性等. this
在Account类中加入下面代码:
public synchronized void process(double hopeGetMoney){ if(money >= hopeGetMoney){ System.out.println(Thread.currentThread().getName()+"取钱成功,取出金额为:"+hopeGetMoney); try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } //修改金额 this.money=money-hopeGetMoney; System.out.println("余额为:"+money); }else{ System.out.println("余额不足,取款失败!"); } }
修改业务类中的run()方法为:
public void run(){ account.process(hopeGetMoney); }印度人A取钱成功,取出金额为:800.0
好比StringBuffer是多线程安全的,但性能很差.StringBuilder有好的性能,但线程是不安全的.
释放:
不释放:
先贴代码,上一章最后的代码,不变,只修改account代码以下:
public class Account { private String account; private double money; private final ReentrantLock lock=new ReentrantLock(); public Account(String account,double money){ this.account=account; this.money=money; } public void process(double hopeGetMoney){ try { lock.lock(); if(money >= hopeGetMoney){ System.out.println(Thread.currentThread().getName()+"取钱成功,取出金额为:"+hopeGetMoney); try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } //修改金额 this.money=money-hopeGetMoney; System.out.println("余额为:"+money); }else{ System.out.println("余额不足,取款失败!"); } } finally { lock.unlock(); } } //根据account重写hashcode和equals方法.使用的是lock.输出为:
印度人A取钱成功,取出金额为:800.0
余额为:200.0
余额不足,取款失败!
Lock是控制多个线程对共享资源进行访问的工具.一般,锁提供了对共享资源的独占访问,每次只能有一个线程对lock对象加锁,线程开始访问共享资源以前应得到Lock对象.
同步锁里面须要理解的东西也不少,这里........尼玛快过年了,实在没心情搞了.
死锁就是两个线程互相等待对方释放同步监视器时就回发生死锁.Java虚拟机没有检测,也没有采起措施来处理死锁状况,因此多线程编程时要注意这个状况.发生死锁的时候,整个程序没错误没异常,没提示,只是说有线程都处于阻塞状态,没法继续.