Java并发编程实例--13.方法同步(synchronized)
使用synchronized关键字去控制对某个方法的并发调用。
某一时段内,只能有一个线程可以读取该方法。
其他线程需要等待前面线程调用完毕后方可调用。
不过,静态方法有着不同的行为。
虽然也是每次只能有一个线程调用它,但是另一个线程可以调用该类对象的其他非静态方法。
这一点需要注意,因为如果2个线程可读取2个不同的同步方法,一个是静态另一个不是。
如果这2个方法修改的是同样的数据,可能会导致数据不一致错误。
本例中,我们将有一个银行账户和2个线程;1个线程存钱,1个线程取钱。这种情况,如果不适用方法同步机制账户里的钱就不对了。方法同步机制保证了账户的最终平衡。
Account.java
package com.dylan.thread.ch2.c01.task;
/**
* This class simulates a bank account
*
*/
public class Account {
/**
* Balance of the bank account
*/
private double balance;
/**
* Returns the balance of the account
* @return the balance of the account
*/
public double getBalance() {
return balance;
}
/**
* Establish the balance of the account
* @param balance the new balance of the account
*/
public void setBalance(double balance) {
this.balance = balance;
}
/**
* Add an import to the balance of the account
* @param amount the import to add to the balance of the account
*/
public synchronized void addAmount(double amount) {
double tmp=balance;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
tmp+=amount;
balance=tmp;
}
/**
* Subtract an import to the balance of the account
* @param amount the import to subtract to the balance of the account
*/
public synchronized void subtractAmount(double amount) {
double tmp=balance;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
tmp-=amount;
balance=tmp;
}
}
Company.java
package com.dylan.thread.ch2.c01.task;
/**
* This class simulates a company that pays a salary an
* insert money into an account
*
*/
public class Company implements Runnable {
/**
* The account affected by the operations
*/
private Account account;
/**
* Constructor of the class. Initializes the account
* @param account the account affected by the operations
*/
public Company(Account account) {
this.account=account;
}
/**
* Core method of the Runnable
*/
public void run() {
for (int i=0; i<100; i++){
account.addAmount(1000);
}
}
}
Bank.java
package com.dylan.thread.ch2.c01.task;
/**
* This class simulates a bank or a cash dispenser that takes money
* from an account
*
*/
public class Bank implements Runnable {
/**
* The account affected by the operations
*/
private Account account;
/**
* Constructor of the class. Initializes the account
* @param account The account affected by the operations
*/
public Bank(Account account) {
this.account=account;
}
/**
* Core method of the Runnable
*/
public void run() {
for (int i=0; i<100; i++){
account.subtractAmount(1000);
}
}
}
Main.java
package com.dylan.thread.ch2.c01.core;
import com.dylan.thread.ch2.c01.task.Account;
import com.dylan.thread.ch2.c01.task.Bank;
import com.dylan.thread.ch2.c01.task.Company;
/**
* Main class of the example. It creates an account, a company and a bank
* to work with the account. The final balance is equal to the initial.
*
*/
public class Main {
/**
* Main method of the example
* @param args
*/
public static void main(String[] args) {
// Creates a new account ...
Account account=new Account();
// an initialize its balance to 1000
account.setBalance(1000);
// Creates a new Company and a Thread to run its task
Company company=new Company(account);
Thread companyThread=new Thread(company);
// Creates a new Bank and a Thread to run its task
Bank bank=new Bank(account);
Thread bankThread=new Thread(bank);
// Prints the initial balance
System.out.printf("Account : Initial Balance: %f\n",account.getBalance());
// Starts the Threads
companyThread.start();
bankThread.start();
try {
// Wait for the finalization of the Threads
companyThread.join();
bankThread.join();
// Print the final balance
System.out.printf("Account : Final Balance: %f\n",account.getBalance());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
Account : Initial Balance: 1000.000000
deposit 1000, balance:2000.0
deposit 1000, balance:3000.0
withdraw 1000, balance:2000.0
withdraw 1000, balance:1000.0
withdraw 1000, balance:0.0
deposit 1000, balance:1000.0
withdraw 1000, balance:0.0
deposit 1000, balance:1000.0
withdraw 1000, balance:0.0
deposit 1000, balance:1000.0
withdraw 1000, balance:0.0
deposit 1000, balance:1000.0
withdraw 1000, balance:0.0
deposit 1000, balance:1000.0
withdraw 1000, balance:0.0
deposit 1000, balance:1000.0
withdraw 1000, balance:0.0
deposit 1000, balance:1000.0
withdraw 1000, balance:0.0
deposit 1000, balance:1000.0
Account : Final Balance: 1000.000000
Java并发编程实例--13.方法同步(synchronized)的更多相关文章
- Java并发编程:线程的同步
Java并发编程:线程的同步 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} J ...
- Java并发编程的4个同步辅助类
Java并发编程的4个同步辅助类(CountDownLatch.CyclicBarrier.Semphore.Phaser) @https://www.cnblogs.com/lizhangyong/ ...
- Java并发编程的4个同步辅助类(CountDownLatch、CyclicBarrier、Semphore、Phaser)
我在<jdk1.5引入的concurrent包>中,曾经介绍过CountDownLatch.CyclicBarrier两个类,还给出了CountDownLatch的演示案例.这里再系统总结 ...
- Java并发编程的4个同步辅助类(CountDownLatch、CyclicBarrier、Semaphore、Phaser)
我在<JDK1.5引入的concurrent包>中,曾经介绍过CountDownLatch.CyclicBarrier两个类,还给出了CountDownLatch的演示案例.这里再系统总结 ...
- Java并发编程(六)-- 同步块
上一节已经讲到,使用Synchronzied代码块可以解决共享对象的竞争问题,其实还有其他的方法也可以避免资源竞争问题,我统称他们为Java同步块.Java 同步块(synchronized bloc ...
- Java并发编程实例(synchronized)
此处用一个小程序来说明一下,逻辑是一个计数器(int i):主要的逻辑功能是,如果同步监视了资源i,则不输出i的值,但如果没有添加关键字synchronized,因为是两个线程并发执行,所以会输出i的 ...
- Java并发编程知识点总结Volatile、Synchronized、Lock实现原理
Volatile关键字及其实现原理 在多线程并发编程中,Volatile可以理解为轻量级的Synchronized,用volatile关键字声明的变量,叫做共享变量,其保证了变量的“可见性”以及“有序 ...
- 【Java并发编程之深入理解】Synchronized的使用
原文:https://blog.csdn.net/zjy15203167987/article/details/82531772 1.为什么要使用synchronized 在并发编程中存在线程安全问题 ...
- 转:【Java并发编程】之七:使用synchronized获取互斥锁的几点说明
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17199201 在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访 ...
- 【Java并发编程】之七:使用synchronized获取互斥锁的几点说明
在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确 ...
随机推荐
- [转帖]xsos - Summarize system info from sosreports
https://github.com/ryran/rsar I'M LOOKING FOR RSAR SCREEN SHOTS INTRO INSTALLATION EXAMPLES IN ACTIO ...
- [转帖]Nacos 获取配置时启用权限认证
默认情况下获取 Nacos 中的配置是不需要权限认证的, 这个估计是由其使用场景决定的(绝大多数都是仅内网可访问). 今天调查了下如何在获取配置时增加权限验证以提高其安全性. 1. 启用 Nacos ...
- TCP内核参数的简单验证
前言 春节假期时学习了下内核参数与nginx的调优 最近因为同事遇到问题一直没有解,自己利用晚上时间再次进行验证. 这里将几个参数的理解和验证结果简单总结一下. 希望能够在学习的过程中将问题解决掉. ...
- Nginx的Keepalive的简单学习
摘要 最近发现某项目的Nginx负载服务器上面有很多Time_wait的TCP连接 可以使用命令 netstat -n |awk '/^tcp/ {++S[$NF]} END{for (a in S) ...
- diff算法是如何比较的,保证让你看的明明白白的!
更新dom节点,最小力度去跟新 index.html <body> <h1>你好啊!</h1> <button id="btn">该 ...
- docker的架构及工作原理(详解)
目录 一.docker架构图 二.Client 客户端 三.Host 主机(docker引擎) 四.Image 镜像 五.Container 容器 六.镜像分层 可写的容器层 七.Volume 数据卷 ...
- CentOS使用iptables开放3000端口
关闭firewall systemctl stop firewalld.service 禁止firewall开机启动 systemctl disable firewalld.service 设置ipt ...
- 物联网浏览器(IoTBrowser)-电子秤模块及二次驱动开发
本章介绍电子秤模块的示例功能以及二次开发称重驱动的代码,二次开发以顶尖OS2型号驱动为示例,实现方式与物联网浏览器(IoTBrowser)-顶尖OS2电子秤协议实现类似,不同的是电子秤只需要采集重量不 ...
- SqlSugar基础查询
查所有 List<Student> list=db.Queryable<Student>().ToList() //select * from Student 查询总数 int ...
- C/C++ 关于运算符重载笔记
加号运算符重载: 重载加号运算符,让 p3 = p1 + p2 改成 p3.mage = p1.mage + p2.mage 实现两个数据成员的相加. 告诉编译器,两个类中的数据成员应该怎么相加. 成 ...