使用synchronized实现同步方法
来源:互联网 发布:数据机房管理制度 编辑:程序博客网 时间:2024/05/16 07:33
在开始本篇前我们先来看个例子,大家可以自己先看看代码想想运行后的结果。
例子说明:
1、在本例中将模拟两个线程(公司、家庭)同时操作账户,公司负责往账户中存钱,家庭负责花钱,循环100次。
2、存钱和花钱时都先取出账户中的钱放入临时变量,然后再将当前线程休眠固定时间,最后将用临时变量的值加减金额后重新赋值给账户。
3、初始账户中有人民币1000元。
package com.sqczm.concurrent.sync;import java.util.concurrent.TimeUnit;/** * <p>Description: 账户 </p> * <p>Copyright: Copyright (c) 2014 </p> * <p>Date: 2014年11月4日 </p> * <p>Company: Ausware </p> * @author ygczm * @version V1.0 */public class Account {private double money;/** * 账户资金 * @return 账户资金 */public double getMoney() {return money;}/** * 账户资金 * @param money 账户资金 */public void setMoney(double money) {this.money = money;}/** * 存钱 * @param num 数量 */public synchronized void addMoney(double num){System.out.println("-->开始存钱......");double temp = money;try {TimeUnit.MILLISECONDS.sleep(21l);} catch (InterruptedException e) {e.printStackTrace();}money = temp + num;System.out.println("-->存钱结束......");}/** * 取钱 * @param num 数量 */public synchronized void subMoney(double num){System.out.println("-->开始取钱......");double temp = money;try {TimeUnit.MILLISECONDS.sleep(19l);} catch (InterruptedException e) {e.printStackTrace();}money = temp - num;System.out.println("-->取钱结束......");}}
package com.sqczm.concurrent.sync;/** * <p>Description: 家庭 </p> * <p>Copyright: Copyright (c) 2014 </p> * <p>Date: 2014年11月4日 </p> * <p>Company: Ausware </p> * @author ygczm * @version V1.0 */public class Family implements Runnable {private Account account;public Family(Account account) {this.account = account;}@Overridepublic void run() {for(int i = 0; i < 100; i++){account.subMoney(1000);}}}
package com.sqczm.concurrent.sync;/** * <p>Description: 公司 </p> * <p>Copyright: Copyright (c) 2014 </p> * <p>Date: 2014年11月4日 </p> * <p>Company: Ausware </p> * @author ygczm * @version V1.0 */public class Company implements Runnable {private Account account;public Company(Account account) {this.account = account;}@Overridepublic void run() {for(int i = 0; i < 100; i++){account.addMoney(1000);}}}
package com.sqczm.concurrent.sync;/** * <p>Description: synchronized的测试类 </p> * <p>Copyright: Copyright (c) 2014 </p> * <p>Date: 2014年11月4日 </p> * <p>Company: Ausware </p> * @author ygczm * @version V1.0 */public class SynchronizedTest {public static void main(String[] args) {//模拟创建一个账户Account account = new Account();account.setMoney(1000);//模拟创建两个线程(公司存钱、家庭花钱)Company company = new Company(account);Family family = new Family(account);Thread companyThread = new Thread(company);Thread familyThread = new Thread(family);//在启动线程前先打印账户信息System.out.println("-->账户中初始余额为 " + account.getMoney());//启动两个线程companyThread.start();familyThread.start();//等待两个线程运行完成try {companyThread.join();familyThread.join();} catch (InterruptedException e) {e.printStackTrace();}//线程运行完毕后打印账户信息System.out.println("-->账户中还剩 " + account.getMoney());}}
看完上面的例子后相信大家会有两种想法:一种就是账户中最后还剩1000元,另一种就是账户中剩余的钱不确定。咱们先不讨论上面的例子运行后的结果是多少,咱们先看看synchronized同步方法的说明:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为synchronized)。
看完了上面的解释后,我们应该都猜到了,在同一时间内不可能同时操作取钱和存钱的操作,也就是说在上面存钱和取钱的两个操作中,共享数据(账户金额)得到了保护,最终我们的账户金额不会受影响。
synchronized关键字会降低应用程序的性能,因此只能在并发情景中需要修改共享数据的方法上使用它。如果多个线程访问同一个synchronized方法,则只有一个线程可以访问,其他线程将等待。如果方法申明中没有使用synchronized关键字,所有的线程都能在同一时间执行这个方法(可将上面的Account类中的存钱或取钱的方法前的synchronized关键字去掉后测试),因而总运行时间将降低。如果已知一个方法不会被一个以上线程调用,则无需使用synchronized关键字申明之。
可以递归调用被synchronized申明的方法。当线程访问一个对象的同步方法时,它还可以调用这个方法对象的其他的同步方法,也包含正在执行的方法,而不必再去获取这个方法的访问权。
- 使用synchronized实现同步方法
- 使用synchronized实现同步方法
- 并发编程--使用synchronized实现同步方法
- 2.1使用synchronized实现同步方法
- 使用synchronized块同步方法..
- 使用Synchronized块同步方法
- 使用Synchronized块同步方法
- 使用Synchronized块同步方法
- 2.1使用synchronized同步方法
- 使用Synchronized关键字同步类方法
- 使用Synchronized关键字同步类方法
- synchronized:线程同步方法使用总结
- 使用synchronized实现同步代码块
- 【多线程】synchronized同步方法
- synchronized同步方法
- Java同步方法synchronized
- java--同步方法(synchronized)
- synchronized同步方法
- 黑马程序员——网络编程之UDP、TCP/IP
- 第10周项目3-血型统计
- hdu4000 && hrbust1625
- NLPIR(ICTCLAS2013) Python版
- Java中serialVersionUID的解释
- 使用synchronized实现同步方法
- 关于HttpClient上传中文乱码的解决办法
- 快速排序
- 同时使用windows和linux系统
- Intent 的Flag属性(Activity在栈位置的主宰者)
- 遍历mysql中所有的数据库和所有的表
- 雅安玛斯诺国际酒店设计
- twisted 定时处理(递归调用callLater)(protocol内)
- Segment