Java多线程(2)—线程同步
介绍了线程的基本概念和方法,终于进入到上一章中介绍的取款问题了。回顾下在支付宝和微信上做了绑定卡之后,查询为3000,此时在支付宝和微信的均取出2000,此时银行卡变成了-1000
那上述取款如何实现呢?
package blog;public class TestAccount {public static void main(String[] args) {Account account = new Account();//多线程对象User u_weixin = new User(account, 2000);User u_zhifubao = new User(account, 2000);Thread weixin = new Thread(u_weixin,"微信账户");Thread zhifubao = new Thread(u_zhifubao,"支付宝账户");weixin.start();zhifubao.start();}
}class Account{public static int money = 3000;//全局变量,共享数据public void takeMoney(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}
}class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() {// TODO Auto-generated method stubaccount.takeMoney(money);}
}
查看输出结果
多线程调用方法时,存在上述问题。线程共享资源时,一个线程在执行方法没有完毕时,另一个线程开始执行这个方法,导致共享数据出错。那如何解决,自然就是让一个线程先执行完成,在执行过程中拒绝其他线程参与执行。就是一个线程一个线程的依次完成执行。
1、方法加入synchronized同步锁
通过在方法上加入关键字synchronized来处理。public synchronized void takeMoney();因此将上述代码中的takeMoney进行改造如下:
class Account{public static int money = 3000;public synchronized void takeMoney(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}
}
此时查看输出结果如下:
注意:在普通方法上加同步锁synchronized,锁的是整个对象,不是某一个方法。如何理解这句话呢,我们将上述的方法进行改造。
1.将takeMoney复制一份命名为takeMoney1
2.将run中加入线程名称判断
package blog;public class TestAccount {public static void main(String[] args) {Account account = new Account();//多线程对象User u_weixin = new User(account, 2000);User u_zhifubao = new User(account, 2000);Thread weixin = new Thread(u_weixin,"微信账户");Thread zhifubao = new Thread(u_zhifubao,"支付宝账户");weixin.start();zhifubao.start();}
}class Account{public static int money = 3000;public synchronized void takeMoney(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}public synchronized void takeMoney1(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}}class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() {// TODO Auto-generated method stub
// account.takeMoney(money);if (Thread.currentThread().getName() == "微信") {account.takeMoney(money);}else {account.takeMoney1(money);}}
}
输出结果:
发现输出结果依然能正确输出,这就是所谓的锁住的是对象,因为我们定义了一个账户对象account。作为对比,新建两个对象,则输出结果如下所示:
综上所述,所以说synchronized锁住的是对象方法。不同的对象是不同的锁,因此线程使用不同对象调用此方法依然有资源共享的问题。
//将Account中的takeMoney进行如下改造public static synchronized void takeMoney2(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}
将User中的方法调整如下
class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() {account.takeMoney2(money);}
}
此时查看输出结果
同static属性和方法是共享的一样,这里加入static synchronized 表示为类的属性/方法。
2.代码块加入同步锁
新增一个takeMoney4方法,并在代码块加入同步锁synchronized
package blog;public class TestAccount {public static void main(String[] args) {Account account = new Account();Account account1 = new Account();//多线程对象User u_weixin = new User(account, 2000);User u_zhifubao = new User(account1, 2000);Thread weixin = new Thread(u_weixin,"微信账户");Thread zhifubao = new Thread(u_zhifubao,"支付宝账户");weixin.start();zhifubao.start();}
}class Account{public static int money = 3000;public synchronized void takeMoney(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}/*** 静态方法加synchronized,对所有对象都是同一个锁* @param m*/public static synchronized void takeMoney2(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}public void takeMoney3(int m) {synchronized(this){//表示当前对象的代码被加入了synchronized同步锁,this表示当前对象String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}}public void takeMoney4(int m) {synchronized(this){//表示当前对象的代码被加入了synchronized同步锁,this表示当前对象String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}}}class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() {// TODO Auto-generated method stub
// account.takeMoney(money);if (Thread.currentThread().getName() == "微信") {account.takeMoney3(money);}else {account.takeMoney4(money);}// account.takeMoney2(money);}
}
依然是用的是两个对象进行调用,输出结果如下:
那如果使用的是一个对象呢?
//多线程对象User u_weixin = new User(account, 2000);User u_zhifubao = new User(account, 2000);
输出如下:
这里的输出结果和使用方法同步锁一样,存在不同的对象出现共享资源有限错误的情况。那同一个对象加入相同的锁,不同的对象加入不同的锁如何实现呢,可以通过对方法传入的对象加入synchronized同步锁,如下所示:
public void takeMoney5(int m,Account a) {synchronized(a){//表示当前对象的代码被加入了synchronized同步锁,this表示当前对象String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,账户金额不足:"+money);}else {System.out.println(name + "操作,账户原有金额:"+money);System.out.println(name + "操作,取款金额:" + m);money = money - m;System.out.println(name + "操作,取款后的余额:" + money);}}}
class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() { account.takeMoney5(money,account);}
}
如果是相同的对象,则输出:
如果是不同的对象,则输出:
因此可有如下结论:
- 普通方法加入同步锁,所得是当前方法对应的对象,当前对象的所有的加了同步锁的方法共用一个同步锁
- 静态方法方法加入同步锁,所有对象公用一个同步锁
- 代码块加入同,如果是synchronized(this)形式,所有当前的对象的synchronized(this)同步的代码使用同一个锁,如果是synchronized(obj)不同的对象使用的不同的锁
Java多线程(2)—线程同步相关推荐
- Java多线程之线程同步机制(锁,线程池等等)
Java多线程之线程同步机制 一.概念 1.并发 2.起因 3.缺点 二.三大不安全案例 1.样例一(模拟买票场景) 2.样例二(模拟取钱场景) 3.样例三(模拟集合) 三.同步方法及同步块 1.同步 ...
- java多线程采集+线程同步-【多线程数据采集之四】
前些日子讲解了java数据抓取, 今天就讲解最核心的. java多线程数据抓取. java多线程采集+数据同步+线程同步[多线程数据采集之四] 主要讲解多线程抓取,多线程同步,多线程启动,控制等操作. ...
- java多线程之线程同步问题
1.线程不安全的问题分析 当多线程并发访问同一个资源对象的时候,可能出现线程不安全的问题.但是,我们分析打印的结果,发现没有问题: 为了让问题更明显: Thread.sleep(10);//当 ...
- Java多线程(线程同步)
多线程编程很容易出现"错误情况",这是由系统的线程调度具有一定的随机性造成的,不过即使程序偶然出现问题,那也是由于编程不当引起.使用多个线程访问同一个数据时很容易出现此类状况,因此 ...
- Java多线程编程——线程同步与线程安全问题及synchronized关键字
在多线程环境下,我们常常需要让多个线程同时去操作同一资源.在某些情况下,这种情形会导致程序的运行结果出现差错.专业上的,当多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不 ...
- java多线程:线程同步synchronized(不同步的问题、队列与锁),死锁的产生和解决
0.不同步的问题 并发的线程不安全问题: 多个线程同时操作同一个对象,如果控制不好,就会产生问题,叫做线程不安全. 我们来看三个比较经典的案例来说明线程不安全的问题. 0.1 订票问题 例如前面说过的 ...
- Java 多线程和线程同步总结
转载:JAVA多线程实现和线程同步总结 1.JAVA多线程实现方式 JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable ...
- Java多线程之线程同步
线程同步 线程同步:当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多. ...
- java多线程、线程同步与线程池
1. 线程的基本概念 1.1 进程 任何的软件存储在磁盘中,运行软件的时候,OS使用IO技术,将磁盘中的软件的文件加载到内存,程序在能运行. 进程的概念 : 应用程序(typora,word,IDEA ...
- Java多线程:线程同步(3)- synchronized关键字
最新文章
- 报名 | AI Time :论道AI安全与伦理
- 为什么Java大神,都在看Spring Boot和Spring Cloud的书?
- 卷积神经网络(CNN)前向传播算法
- 麦田在线携手网易云信,开启手机智能找房新时代
- 机器学习相关——SVD分解
- 51CTO-redis-集群安装以及动态扩容
- 大咖说|翼辉丁晓华:我们已经真正意义上感受到了原始创新带来的巨大价值
- ceph的 cache tier实现分析
- liunx安装xfs包挂载大于16T的硬盘
- Android Studio 关于android resource linking failed的报错解决方法
- Class的基本语法
- 绝对良心提供百度网盘的jdk1.8源码下载包含sun包的
- 原创 | 假期必读:一文看尽2019-2020各大顶会GNN论文(附链接)
- 树莓派有can通信吗_树莓派 RS485 CAN HAT模块使用
- 群晖设置公网ipv6方式域名解析访问
- 关于ETD.sys的系统蓝屏问题的解决
- 想买折叠手机的你,了解OLED显示很有必要
- wxd719() :大大您的方法有一点小问题:我设成每页35行,在分组区用GROUPNUMBER MOD 1 =0强制分组从新页开始,加上你的recordNumber mod
- WINDOWS网络服务第一章预习导图
- 微信小程序清除缓存clearStorageSync和removeStorageSync的区别 清除缓存问题 数据缓存详解
热门文章
- Android中WebView的跨域漏洞分析和应用被克隆问题情景还原(免Root获取应用沙盒数据)...
- day05 Spring中自定义注解的用处-之获取自定义的Servie
- 树莓派debian配置lamp[解决Apache不显示php网页]
- python继承——封装
- WEB-INF目录与META-INF目录的作用
- Eclipse中查看没有源码的Class文件的方法
- Access转Sql Server问题
- stm32f103插拔pc端的串口引起的问题及解决办法
- STM32f103 can的两个接收fifo使用方法
- C++ Primer 5th笔记(chap 16 模板和泛型编程)模板实参推断