Java线程同步
2015-06-28 11:04
666 查看
Java线程同步
使用synchronized来同步方法
一个模拟银行账户取款增款的例子
该例子共有4个类,分别是Account(账户类),Bank(取款),Company(增款),Client(用户)。Bank类会模拟100次取款,每次1000,Company类会模拟100次增款,每次1000。用户初始账户为1000,所以正确情况应该是余额依然为1000。下面是Account源代码:
package com.zk; public class Account { /** 余额 **/ private double balance; /** 查询余额 **/ public double getBalance(){ return balance; } /** 设置余额 **/ public void setBalance(double balance){ this.balance = balance; } /** 增加余额 **/ public synchronized void addAmount(double amount){ double tmp = balance; try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } tmp += amount; balance = tmp; } /** 减少余额**/ public synchronized void substractAmount(double amount){ double tmp = amount; try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } tmp -= amount; balance = tmp; } }
Bank代码:
package com.zk; /** 从银行中取款 **/ public class Bank implements Runnable { private Account account; public Bank(Account account){ this.account = account; } @Override public void run() { for(int i=0; i<100; ++i){ account.substractAmount(1000); } } }
Company代码:
package com.zk; /** 公司会发工资 **/ public class Company implements Runnable { private Account account; public Company(Account account){ this.account = account; } @Override public void run() { for(int i=0; i<100; ++i){ account.addAmount(1000); } } }
Client代码:
package com.zk; public class Client { public static void main(String[] args) { //初始账户:1000元 Account account = new Account(); account.setBalance(1000); Company company = new Company(account); Thread companyThread = new Thread(company); Bank bank = new Bank(account); Thread bankThread = new Thread(bank); System.out.printf("Account: Initial Balance: %f.\n", account.getBalance()); //启动两个线程:模拟100次存款(每次1000),100次取款(每次1000) companyThread.start(); bankThread.start(); try { //使用join方法来等待两个线程结束(die) companyThread.join(); bankThread.join(); System.out.printf("Account: Final Balance: %f.\n.", account.getBalance()); } catch (InterruptedException e) { e.printStackTrace(); } } }
多次运行结果如下:
通过
Thread.sleep(10)我们来模拟取款增款时的一个延时。
在去掉
addAmount()和
substractAmount()前面的关键字
synchronized以后,当我们再次执行,会发现出现了错误的结果,而且每次结果不一样。这是因为JVM是不保证线程执行顺序,所以每次运行结果不一样。
而当我们添加上
synchronized关键字的时候,这个时候当线程A正在执行
Account类中标有
synchronized方法的时候,如果有其他线程想同时执行
synchronized方法,那么它将会阻塞直至线程A所正在执行的
synchronized方法结束。同一时刻,只能有一个线程执行一个类中的一个
synchronized方法。
在实际使用中,可以使用
synchronized来锁一部分代码,而不是整个方法:
synchronized(this){ //... }
而且这样还可以根据需要来锁定不同的对象,而不是整个类:
private final Object cinemaA = new Object(); private final Object cinemaB = new Object(); /** 影院A销售票,锁定cinemaA对象即可 **/ public void cinemaASellTickets(){ synchronized(cinemaA) { //... } } /** 影院B销售票,锁定cinemaB对象即可 **/ public void clinemaBSellTickets(){ synchronized(cinemaB){ //... } }
在synchronized代码块中使用条件
相关文章推荐
- Spring配置web.xml中<listener>标签(ContextLoaderListener类解析)解析
- Java报错系列――java.util.Date/java.sql.Date/java.sql.Timestamp
- java中遇到过的String的一些特性
- Struts框架刷新验证之基于xml配置方式
- Java知多少(106)程序与数据库连接
- spring集成struts2
- Spring中@Autowired注解、@Resource注解的区别
- 【JavaWeb】(2)JSP内置对象
- 深入入门正则表达式(java) - 匹配原理 - 2 - 回溯
- java 动态代理范例 InvocationHandler与Proxy
- 获取JDK动态代理/CGLIB代理对象代理的目标对象。
- jdk环境变量配置
- Java中this关键字的几种用法(转)
- Java -- 算法小结之希尔排序
- Spring整合Strut2小结
- 2015062805 - EffactiveJava笔记 - 第41条 慎用重载(1)
- 使用eclipse编译和管理live555源码
- jsp显示java后台的异常
- eclipse运行jsp程序错误---SEVERE: StandardServer.await: create[localhost:8005]
- Java内部类总结