线程的同步
案例:
同一个 账户金额3000,支付宝与微信同时取钱2000,导致余额-1000
支付宝与微信异步执行:
package ThreadTest;
/**
* 同一个 账户金额3000实现支付宝与微信同时取钱2000
* @author doer
*
*/
public class Test2 {
public static void main(String[] args) {
//同一个账户
Acount acount=new Acount();
//创建两个多线程User对象
User u_zhi=new User(acount, 2000);
User u_wei=new User(acount, 2000);
//构建线程
Thread weixin=new Thread(u_wei,"微信");
Thread zhifubao=new Thread(u_zhi,"支付宝");
//开启线程
weixin.start();
zhifubao.start();
}
}
/**
* 封装取钱操作
* 异步性:多线程调用方法时,一个线程没有执行完,另一个线程又开始执行:导致支付宝微信同时取钱
* 解决思路:加锁:同步锁:使一个线程具有原子性
* 直接在执行的方法上加synchronized同步锁
* @author douer
*
*/
class Acount{
//账户余额
public static int money=3000;
/**
* 用于判断账户余额是否够取
*/
public /*synchronized*/ void drawing(int m) {
//当前运行线程的名字:支付宝or
String name=Thread.currentThread().getName();
//取钱数目超过余额
if(money<m) {
System.out.println(name+"操作:账户金额不足,余额为:"+money);
}else {
System.out.println(name+"操作:账户原有金额:"+money);
money-=m;
System.out.println(name+"操作:账户提款金额:"+m);
System.out.println(name+"操作:账户提款之后金额:"+money);
}
}
}
class User implements Runnable{
//账户对象
Acount acount;
int money;
//构造用户对象
public User(Acount acount,int money) {
this.acount=acount;
this.money=money;
}
@Override
public void run() {
acount.drawing(money); //进行取钱操作 money是取钱的数目
}
}
synchronized同步锁
锁住方法:
-
锁的是整个对象,不是某一个方法
-
所以方法不同,同步锁也会起作用
比如:acount对象被锁住,尽管支付宝与微信调用不同的方法处理acount进行取款,acount的提款执行还是具有原子性
User://同一个对象acount分别调用drawing0和drawing1 if(Thread.currentThread().getName().equals("zhifubao")) { acount.drawing0(money); }else { acount.drawing1(money);
class Acount{
//账户余额
public static int money=3000;/** * 用于判断账户余额是否够取 */ public synchronized void drawing1(int m) { //当前运行线程的名字:支付宝or String name=Thread.currentThread().getName(); //取钱数目超过余额 if(money<m) { System.out.println(name+"操作:账户金额不足,余额为:"+money); }else { System.out.println(name+"操作:账户原有金额:"+money); money-=m; System.out.println(name+"操作:账户提款金额:"+m); System.out.println(name+"操作:账户提款之后金额:"+money); } } public synchronized void drawing0(int m) { //当前运行线程的名字:支付宝or String name=Thread.currentThread().getName(); //取钱数目超过余额 if(money<m) { System.out.println(name+"操作:账户金额不足,余额为:"+money); }else { System.out.println(name+"操作:账户原有金额:"+money); money-=m; System.out.println(name+"操作:账户提款金额:"+m); System.out.println(name+"操作:账户提款之后金额:"+money); } }
Main:
public static void main(String[] args) {
//同一个账户
Acount acount=new Acount();//创建两个多线程User对象 User u_zhi=new User(acount, 2000); User u_wei=new User(acount, 2000); //构建线程 Thread weixin=new Thread(u_wei,"微信"); Thread zhifubao=new Thread(u_zhi,"支付宝"); //开启线程 weixin.start(); zhifubao.start(); }
-
-
普通方法中添加同步锁::对于不同的对象(如acount),将会使用不同的同步锁===不起作用
Acount加锁:
public synchronized void drawing0(int m) {
//当前运行线程的名字:支付宝or
String name=Thread.currentThread().getName();//取钱数目超过余额 if(money<m) { System.out.println(name+"操作:账户金额不足,余额为:"+money); }else { System.out.println(name+"操作:账户原有金额:"+money); money-=m; System.out.println(name+"操作:账户提款金额:"+m); System.out.println(name+"操作:账户提款之后金额:"+money); } } public synchronized void drawing1(int m) { //当前运行线程的名字:支付宝or String name=Thread.currentThread().getName(); //取钱数目超过余额 if(money<m) { System.out.println(name+"操作:账户金额不足,余额为:"+money); }else { System.out.println(name+"操作:账户原有金额:"+money); money-=m; System.out.println(name+"操作:账户提款金额:"+m); System.out.println(name+"操作:账户提款之后金额:"+money); } }
Main:
public class Test2 {
public static void main(String[] args) {
//2个账户
Acount acount=new Acount();
Acount acount2=new Acount();//创建两个多线程User对象 User u_zhi=new User(acount, 2000); User u_wei=new User(acount2, 2000); //构建线程 Thread weixin=new Thread(u_wei,"微信"); Thread zhifubao=new Thread(u_zhi,"支付宝"); //开启线程 weixin.start(); zhifubao.start(); } }
User:
//支付宝的调用方法
if(Thread.currentThread().getName().equals(“zhifubao”)) {
acount.drawing0(money);
}else {//微信的调用方法
acount.drawing1(money);
} -
静态方法加锁::对于所有对象都可以可以起作用
锁住代码块
-
synchronized(this) 代表当前对象;
-
如果有其他代码块(可以是另一个方法中的代码块)也加了锁,则使用的是同一个锁
public void drawing2(int m) {
synchronized(this) {
//当前运行线程的名字:支付宝or
String name=Thread.currentThread().getName();//取钱数目超过余额 if(money<m) { System.out.println(name+"操作:账户金额不足,余额为:"+money); }else { System.out.println(name+"操作:账户原有金额:"+money); money-=m; System.out.println(name+"操作:账户提款金额:"+m); System.out.println(name+"操作:账户提款之后金额:"+money); } } }
-
-
synchronized(a) :用于不同的对象进行加锁,传入哪个对象就为不同的对象加锁
/** * 给不同对象加锁:synchronized(acount) * @param m * @param acount */ public void drawing6(int m,Acount acount) { synchronized(acount) {//给不同对象加锁 String name=Thread.currentThread().getName(); //取钱数目超过余额 if(money<m) { System.out.println(name+"操作:账户金额不足,余额为:"+money); }else { System.out.println(name+"操作:账户原有金额:"+money); money-=m; System.out.println(name+"操作:账户提款金额:"+m); System.out.println(name+"操作:账户提款之后金额:"+money); } } }
main:
public class Test2 {
public static void main(String[] args) {
//同一个账户
Acount acount=new Acount();
Acount acount2=new Acount();//创建两个多线程User对象 User u_zhi=new User(acount, 2000); User u_wei=new User(acount2, 2000); //构建线程 Thread weixin=new Thread(u_wei,"微信"); Thread zhifubao=new Thread(u_zhi,"支付宝"); //开启线程 weixin.start(); zhifubao.start(); } }
User:
acount.drawing6(money,acount);//传入不同的账户,同步锁的参数不同,给响应的对象分别加锁总结:
- 对对象加锁就加在方法上
- 对某一段代码加锁就直接在代码块加锁