介绍了线程的基本概念和方法,终于进入到上一章中介绍的取款问题了。回顾下在支付宝和微信上做了绑定卡之后,查询为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);}
}

如果是相同的对象,则输出:

如果是不同的对象,则输出:

因此可有如下结论:

  1. 普通方法加入同步锁,所得是当前方法对应的对象,当前对象的所有的加了同步锁的方法共用一个同步锁
  2. 静态方法方法加入同步锁,所有对象公用一个同步锁
  3. 代码块加入同,如果是synchronized(this)形式,所有当前的对象的synchronized(this)同步的代码使用同一个锁,如果是synchronized(obj)不同的对象使用的不同的锁

Java多线程(2)—线程同步相关推荐

  1. Java多线程之线程同步机制(锁,线程池等等)

    Java多线程之线程同步机制 一.概念 1.并发 2.起因 3.缺点 二.三大不安全案例 1.样例一(模拟买票场景) 2.样例二(模拟取钱场景) 3.样例三(模拟集合) 三.同步方法及同步块 1.同步 ...

  2. java多线程采集+线程同步-【多线程数据采集之四】

    前些日子讲解了java数据抓取, 今天就讲解最核心的. java多线程数据抓取. java多线程采集+数据同步+线程同步[多线程数据采集之四] 主要讲解多线程抓取,多线程同步,多线程启动,控制等操作. ...

  3. java多线程之线程同步问题

    1.线程不安全的问题分析 当多线程并发访问同一个资源对象的时候,可能出现线程不安全的问题.但是,我们分析打印的结果,发现没有问题: 为了让问题更明显:     Thread.sleep(10);//当 ...

  4. Java多线程(线程同步)

    多线程编程很容易出现"错误情况",这是由系统的线程调度具有一定的随机性造成的,不过即使程序偶然出现问题,那也是由于编程不当引起.使用多个线程访问同一个数据时很容易出现此类状况,因此 ...

  5. Java多线程编程——线程同步与线程安全问题及synchronized关键字

    在多线程环境下,我们常常需要让多个线程同时去操作同一资源.在某些情况下,这种情形会导致程序的运行结果出现差错.专业上的,当多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不 ...

  6. java多线程:线程同步synchronized(不同步的问题、队列与锁),死锁的产生和解决

    0.不同步的问题 并发的线程不安全问题: 多个线程同时操作同一个对象,如果控制不好,就会产生问题,叫做线程不安全. 我们来看三个比较经典的案例来说明线程不安全的问题. 0.1 订票问题 例如前面说过的 ...

  7. Java 多线程和线程同步总结

    转载:JAVA多线程实现和线程同步总结 1.JAVA多线程实现方式 JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable ...

  8. Java多线程之线程同步

    线程同步 线程同步:当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多. ...

  9. java多线程、线程同步与线程池

    1. 线程的基本概念 1.1 进程 任何的软件存储在磁盘中,运行软件的时候,OS使用IO技术,将磁盘中的软件的文件加载到内存,程序在能运行. 进程的概念 : 应用程序(typora,word,IDEA ...

  10. Java多线程:线程同步(3)- synchronized关键字

最新文章

  1. 报名 | AI Time :论道AI安全与伦理
  2. 为什么Java大神,都在看Spring Boot和Spring Cloud的书?
  3. 卷积神经网络(CNN)前向传播算法
  4. 麦田在线携手网易云信,开启手机智能找房新时代
  5. 机器学习相关——SVD分解
  6. 51CTO-redis-集群安装以及动态扩容
  7. 大咖说|翼辉丁晓华:我们已经真正意义上感受到了原始创新带来的巨大价值
  8. ceph的 cache tier实现分析
  9. liunx安装xfs包挂载大于16T的硬盘
  10. Android Studio 关于android resource linking failed的报错解决方法
  11. Class的基本语法
  12. 绝对良心提供百度网盘的jdk1.8源码下载包含sun包的
  13. 原创 | 假期必读:一文看尽2019-2020各大顶会GNN论文(附链接)
  14. 树莓派有can通信吗_树莓派 RS485 CAN HAT模块使用
  15. 群晖设置公网ipv6方式域名解析访问
  16. 关于ETD.sys的系统蓝屏问题的解决
  17. 想买折叠手机的你,了解OLED显示很有必要
  18. wxd719() :大大您的方法有一点小问题:我设成每页35行,在分组区用GROUPNUMBER MOD 1 =0强制分组从新页开始,加上你的recordNumber mod
  19. WINDOWS网络服务第一章预习导图
  20. 微信小程序清除缓存clearStorageSync和removeStorageSync的区别 清除缓存问题 数据缓存详解

热门文章

  1. Android中WebView的跨域漏洞分析和应用被克隆问题情景还原(免Root获取应用沙盒数据)...
  2. day05 Spring中自定义注解的用处-之获取自定义的Servie
  3. 树莓派debian配置lamp[解决Apache不显示php网页]
  4. python继承——封装
  5. WEB-INF目录与META-INF目录的作用
  6. Eclipse中查看没有源码的Class文件的方法
  7. Access转Sql Server问题
  8. stm32f103插拔pc端的串口引起的问题及解决办法
  9. STM32f103 can的两个接收fifo使用方法
  10. C++ Primer 5th笔记(chap 16 模板和泛型编程)模板实参推断