同步代码块:
文件并发被访问时容易造成异常。

同步代码块语法格式:
synchronized(obj)  
{
    ...
     //此处的代码就是同步代码块
}

obj是同步监视器 线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。

注:任何时刻只能有一条线程可以获得对同步监视器的锁定,当同步代码块执行结束后,该线程自然释放了对该同步监视器的锁定。
通常推荐使用可能被并发访问的共享资源充当同步监视器。

例:

  1. /*
  2. 模拟银行用户取钱问题
  3. */
  4. public class DrawThread extends Thread
  5. {
  6. //模拟用户帐户
  7. private Account account;
  8. //当前取钱线程所希望取的钱数
  9. private double drawAmount;
  10. public DrawThread(String name,Account account,double drawAmout)
  11. {
  12. super(name);
  13. this.account = account;
  14. this.drawAmount = drawAmount;
  15. }
  16. //当多条线程修改同一个共享数据时,涉及安全问题
  17. public void run()
  18. {
  19. //account作为同步监视器
  20. synchronized(account)
  21. {
  22. //帐户余额大于取钱钱数
  23. if(account.getBalance() >= drawAmount)
  24. {
  25. System.out.println(getName() +"取钱成功!吐出钞票:" + drawAmount);
  26. try
  27. {
  28. Thread.sleep(1);
  29. }
  30. catch(InterruptedException ex)
  31. {
  32. ex.printStackTrace();
  33. }
  34. //修改余额
  35. account.setBalance(account.getBalance() - drawAmount);
  36. System.out.println("\t余额为:"+ account.getBalance());
  37. }
  38. else
  39. {
  40. System.out.println(getName()+"取钱失败!余额不足!");
  41. }
  42. }
  43. //同步代码块结束,该线程释放同步锁
  44. }
  45. }

同步方法:

同步方法就是使用synchronized关键字来修饰某个方法,则该方法称为同步方法。
同步方法无需显示指出同步监视器,同步方法的同步监视器就是this,也就是该方法本身。
例:

  1. public class Account
  2. {
  3. private String accountNo;
  4. private double balance;
  5. public Account(){}
  6. public Account(String accountNo,double balance)
  7. {
  8. this.accountNo = accountNo;
  9. this.balance = balance;
  10. }
  11. //此处省略了accountNo的setter和getter方法
  12. //因此余额帐户不允许随便修改,所以取消balance属性的setter方法
  13. public double getBalance()
  14. {
  15. return this.balance;
  16. }
  17. //提供一个线程安全draw方法来完成取钱操作
  18. public synchronized void draw(double drawAmount)
  19. {
  20. //帐户余额大于取钱数目
  21. if(balance >= drawAmount)
  22. {
  23. //吐出钞票
  24. System.out.println(Thread.currentThread().getName() + "取钱成功!吐出钞票:"+ drawAmount);
  25. try
  26. {
  27. Thread.sleep(1);
  28. }
  29. catch(InterruptedException ex)
  30. {
  31. ex.printStackTrace();
  32. }
  33. //修改余额
  34. balance -= drawAmount;
  35. System.out.println("\t 余额为:"+ balance);
  36. }
  37. else
  38. {
  39. System.out.println(Thread.currentThread().getName() +"取钱失败!余额不足!");
  40. }
  41. }
  42. //此处省略了hashCode和equals两个重写的方法。
  43. ...
  44. }

注:synchronized关键字可以修饰方法,可以修饰代码块,但不能修饰构造器,属性等。

释放同步监视器的锁定:

线程会在如下几种情况下释放对同步监视器的锁定:
1.当前线程的同步方法、同步代码块执行结束,当前线程即释放同步监视器。
2.当线程在同步代码块、同步方法中遇到break,return终止了该代码块、该方法的继续执行,
当前线程将会释放同步监视器。
3.当线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致了该代码块、该方法异常结束时将会释放同步监视器。
4.当线程执行同步代码块或同步方法时,程序执行了同步监视器对象的wait()方法,则当前线程暂停,并释放同步监视器。

在下面情况下,线程不会释放同步监视器:
1、线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法来暂停当前线程的执行,当前线程不会释放同步监视器。
2、线程执行同步代码块时,其他线程调用了该线程的suspend方法将该线程挂起,该线程不会释放同步监视器。(应尽量避免)

同步锁(Lock):
使用方法:

  1. 使用Lock对象的代码格式如下:
  2. //ReentrantLock 可重入锁
  3. class X
  4. {
  5. //定义锁对象
  6. private final ReentrantLock lock = new ReentrantLock();
  7. //..
  8. //定义需要保证线程安全的方法
  9. public void m()
  10. {
  11. //加锁
  12. lock.locl();
  13. try
  14. {
  15. //需要保证线程安全的代码
  16. //...method body
  17. }
  18. //使用finally块来保证释放锁
  19. finally
  20. {
  21. lock.unlock();
  22. }
  23. }
  24. }

例:

  1. public class Account
  2. {
  3. //定义锁对象
  4. private final ReentrantLock lock = new ReentrantLock();
  5. private String accountNo;
  6. private double balance;
  7. public Account(){};
  8. public Account(String accountNo,double balance)
  9. {
  10. this.accountNo = accountNo;
  11. this.balance = balance;
  12. }
  13. //此处省略了accountNo的setter和getter方法
  14. //因此帐户余额不允许随便修改,所以取消balance属性的setter方法,
  15. public double getBalance()
  16. {
  17. return this.balance;
  18. }
  19. //提供一个线程安全draw方法来完成取钱操作
  20. public void draw(double drawAmount)
  21. {
  22. //对同步锁进行加锁
  23. lock.lock();
  24. try
  25. {
  26. //帐户余额大于取钱数目
  27. if(balance >= drawAmount)
  28. {
  29. //吐出钞票
  30. System.out.println(Thread.currentThread().getName() + "取钱成功!吐出钞票:"+ drawAmount);
  31. try
  32. {
  33. Thread.sleep(1);
  34. }
  35. catch(InterruptedException ex)
  36. {
  37. ex.printStackTrace();
  38. }
  39. //修改余额
  40. balance -= drawAmount;
  41. System.out.println("\t 余额为:"+ balance);
  42. }
  43. else
  44. {
  45. System.out.println(Thread.currentThread().getName()+"取钱失败!余额不足");
  46. }
  47. }
  48. //使用finally块开确保释放锁
  49. finally
  50. {
  51. lock.unlock();
  52. }
  53. }
  54. //此处省略了hashCode和equals两个重写的方法。
  55. ...
  56. }

注:使用Lock与使用同步方法有点相似,只是使用Lock时显示使用Lock对象作为同步锁,而使用同步方式时系统饮式使用当前对象作为监视器,同样符合“加锁->访问->释放锁”的操作模式,而且使用Lock对象时每个Lock对象对应一个Account对象,一样可以保证对于同一个Account对象,同一时刻只能有一条线程能进入临界区。

ReentrantLock锁具有重入性,也就是说线程可以对他已经加锁的ReentrantLock锁再次加锁,线程在每次调用lock()加锁后,必须显示调用unlock()来释放锁,所以一段被锁保护的代码可以调用另一个被相同锁保护的方法。

转载于:https://blog.51cto.com/chengxuyuan/1034833

疯狂java学习笔记1023---线程的同步相关推荐

  1. 疯狂Java学习笔记(69)---------Lock

    疯狂Java学习笔记(69)---------Lock Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java ...

  2. java学习笔记15--多线程编程基础2

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note15.html,转载请注明源地址. 线程的生命周期 1.线程的生命周期 线程从产生到消亡 ...

  3. java学习笔记14--多线程编程基础1

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为 ...

  4. 疯狂java学习笔记

    <疯狂java>我觉得是一本很好的java基础书,里面解释的比较通俗易懂,不繁琐,深入程度刚刚好,比较适合我现阶段来学习,巩固java基础知识,所以将所做的笔记整理如下: 1.数据类型分类 ...

  5. 0040 Java学习笔记-多线程-线程run()方法中的异常

    run()与异常 不管是Threade还是Runnable的run()方法都没有定义抛出异常,也就是说一条线程内部发生的checked异常,必须也只能在内部用try-catch处理掉,不能往外抛,因为 ...

  6. 【Java学习笔记】线程学习笔记

    一.资源 http://blog.csdn.net/axman/article/details/431796 这个博客里有Java多线程.线程池的一系列,从基础开始就很清楚,牛人 二.重点 今天读到了 ...

  7. Java学习笔记16-多线程

    1.多线程         进程:执行中的程序叫做进程(Process),是一个动态的概念.为了使计算机程序得以运行,计算机需要加载代码,同时也要加载数据,每个进程由3部分组成:cpu,data,co ...

  8. java学习笔记之线程(一)

    线程(一) 一.线程定义于组成: 1.创建任务和线程: 1 TaskThread task = new TaskThread(); // 创建任务 2 Thread taskThread = new ...

  9. 疯狂java学习笔记之面向对象(二) - 成员变量与局部变量

    Java变量按其作用域可分为:成员变量和局部变量.注意:在Java中是没有全局变量这个概念的 一.成员变量: 成员变量是在类中定义的变量,具体可分为类变量与实例变量--有无static修饰 实例变量的 ...

最新文章

  1. 从业5年,教你学习Linux开发
  2. 云计算如何帮助直播行业发展
  3. python软件怎么用-python软件怎么用
  4. C语言再学习 -- 位、字节、字、字长、字元的关系
  5. MongoDB配置参数说明
  6. .NET 6 全新指标 System.Diagnostics.Metrics 介绍
  7. 纯干货 | UI界面中按钮设计CTA按钮\订阅按钮
  8. 八年级计算机考操作试题,八年级计算机会考必看试题!!!!!!
  9. Java面试官:Kafka集群管理
  10. ❤️区块链Hyperledger Fabric 老版本 1.1.0 快速部署安装 教程合集❤️
  11. 使用一个运放滤三次谐波 二阶有源带通滤波器的电路设计及波形效果
  12. adc0809工作过程C语言,ADC0809引脚图、时序图、工作流程图详解
  13. Solr---string类型的docValues属性、stored属性
  14. 极限挑战 极致突破——奇安信的2022
  15. 随身理财专家“挖财”推iPad应用,新增帐号对比功能
  16. 小学生五星分期,钉钉在线求饶
  17. 【嵌入式】51单片机+1602+dht11显示温湿度
  18. 毫米波雷达技术应用,飞睿科技人体存在感应检测模块
  19. jconsole本地连接失败
  20. vue 调用webservice_用C#通过反射实现动态调用WebService 告别Web引用(转载)

热门文章

  1. 深度学习(07)-- 经典CNN网络结构(Inception (v1-v4))
  2. 《Java8实战》笔记汇总
  3. Java web后端5 JSP技术
  4. Android MotionEvent中getX()、getRawX()和getTop()的区别
  5. .NET技术+25台服务器怎样支撑世界第54大网站
  6. 广州驾考科目三电子考16日全面启动
  7. 转载给ffmpeg入门级:我的第一个调用FFmpeg库的程序出炉
  8. MPEG音视频编解码之MP3编解码概述
  9. ffmpeg和SDL学习笔记
  10. jws 方式表格导出,excel文件导出,rest风格接口实现