疯狂java学习笔记1023---线程的同步
同步代码块:
文件并发被访问时容易造成异常。
同步代码块语法格式:
synchronized(obj)
{
...
//此处的代码就是同步代码块
}
obj是同步监视器 线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。
注:任何时刻只能有一条线程可以获得对同步监视器的锁定,当同步代码块执行结束后,该线程自然释放了对该同步监视器的锁定。
通常推荐使用可能被并发访问的共享资源充当同步监视器。
例:
- /*
- 模拟银行用户取钱问题
- */
- public class DrawThread extends Thread
- {
- //模拟用户帐户
- private Account account;
- //当前取钱线程所希望取的钱数
- private double drawAmount;
- public DrawThread(String name,Account account,double drawAmout)
- {
- super(name);
- this.account = account;
- this.drawAmount = drawAmount;
- }
- //当多条线程修改同一个共享数据时,涉及安全问题
- public void run()
- {
- //account作为同步监视器
- synchronized(account)
- {
- //帐户余额大于取钱钱数
- if(account.getBalance() >= drawAmount)
- {
- System.out.println(getName() +"取钱成功!吐出钞票:" + drawAmount);
- try
- {
- Thread.sleep(1);
- }
- catch(InterruptedException ex)
- {
- ex.printStackTrace();
- }
- //修改余额
- account.setBalance(account.getBalance() - drawAmount);
- System.out.println("\t余额为:"+ account.getBalance());
- }
- else
- {
- System.out.println(getName()+"取钱失败!余额不足!");
- }
- }
- //同步代码块结束,该线程释放同步锁
- }
- }
同步方法:
同步方法就是使用synchronized关键字来修饰某个方法,则该方法称为同步方法。
同步方法无需显示指出同步监视器,同步方法的同步监视器就是this,也就是该方法本身。
例:
- public class Account
- {
- private String accountNo;
- private double balance;
- public Account(){}
- public Account(String accountNo,double balance)
- {
- this.accountNo = accountNo;
- this.balance = balance;
- }
- //此处省略了accountNo的setter和getter方法
- //因此余额帐户不允许随便修改,所以取消balance属性的setter方法
- public double getBalance()
- {
- return this.balance;
- }
- //提供一个线程安全draw方法来完成取钱操作
- public synchronized void draw(double drawAmount)
- {
- //帐户余额大于取钱数目
- if(balance >= drawAmount)
- {
- //吐出钞票
- System.out.println(Thread.currentThread().getName() + "取钱成功!吐出钞票:"+ drawAmount);
- try
- {
- Thread.sleep(1);
- }
- catch(InterruptedException ex)
- {
- ex.printStackTrace();
- }
- //修改余额
- balance -= drawAmount;
- System.out.println("\t 余额为:"+ balance);
- }
- else
- {
- System.out.println(Thread.currentThread().getName() +"取钱失败!余额不足!");
- }
- }
- //此处省略了hashCode和equals两个重写的方法。
- ...
- }
注:synchronized关键字可以修饰方法,可以修饰代码块,但不能修饰构造器,属性等。
释放同步监视器的锁定:
线程会在如下几种情况下释放对同步监视器的锁定:
1.当前线程的同步方法、同步代码块执行结束,当前线程即释放同步监视器。
2.当线程在同步代码块、同步方法中遇到break,return终止了该代码块、该方法的继续执行,
当前线程将会释放同步监视器。
3.当线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致了该代码块、该方法异常结束时将会释放同步监视器。
4.当线程执行同步代码块或同步方法时,程序执行了同步监视器对象的wait()方法,则当前线程暂停,并释放同步监视器。
在下面情况下,线程不会释放同步监视器:
1、线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法来暂停当前线程的执行,当前线程不会释放同步监视器。
2、线程执行同步代码块时,其他线程调用了该线程的suspend方法将该线程挂起,该线程不会释放同步监视器。(应尽量避免)
同步锁(Lock):
使用方法:
- 使用Lock对象的代码格式如下:
- //ReentrantLock 可重入锁
- class X
- {
- //定义锁对象
- private final ReentrantLock lock = new ReentrantLock();
- //..
- //定义需要保证线程安全的方法
- public void m()
- {
- //加锁
- lock.locl();
- try
- {
- //需要保证线程安全的代码
- //...method body
- }
- //使用finally块来保证释放锁
- finally
- {
- lock.unlock();
- }
- }
- }
例:
- public class Account
- {
- //定义锁对象
- private final ReentrantLock lock = new ReentrantLock();
- private String accountNo;
- private double balance;
- public Account(){};
- public Account(String accountNo,double balance)
- {
- this.accountNo = accountNo;
- this.balance = balance;
- }
- //此处省略了accountNo的setter和getter方法
- //因此帐户余额不允许随便修改,所以取消balance属性的setter方法,
- public double getBalance()
- {
- return this.balance;
- }
- //提供一个线程安全draw方法来完成取钱操作
- public void draw(double drawAmount)
- {
- //对同步锁进行加锁
- lock.lock();
- try
- {
- //帐户余额大于取钱数目
- if(balance >= drawAmount)
- {
- //吐出钞票
- System.out.println(Thread.currentThread().getName() + "取钱成功!吐出钞票:"+ drawAmount);
- try
- {
- Thread.sleep(1);
- }
- catch(InterruptedException ex)
- {
- ex.printStackTrace();
- }
- //修改余额
- balance -= drawAmount;
- System.out.println("\t 余额为:"+ balance);
- }
- else
- {
- System.out.println(Thread.currentThread().getName()+"取钱失败!余额不足");
- }
- }
- //使用finally块开确保释放锁
- finally
- {
- lock.unlock();
- }
- }
- //此处省略了hashCode和equals两个重写的方法。
- ...
- }
注:使用Lock与使用同步方法有点相似,只是使用Lock时显示使用Lock对象作为同步锁,而使用同步方式时系统饮式使用当前对象作为监视器,同样符合“加锁->访问->释放锁”的操作模式,而且使用Lock对象时每个Lock对象对应一个Account对象,一样可以保证对于同一个Account对象,同一时刻只能有一条线程能进入临界区。
ReentrantLock锁具有重入性,也就是说线程可以对他已经加锁的ReentrantLock锁再次加锁,线程在每次调用lock()加锁后,必须显示调用unlock()来释放锁,所以一段被锁保护的代码可以调用另一个被相同锁保护的方法。
转载于:https://blog.51cto.com/chengxuyuan/1034833
疯狂java学习笔记1023---线程的同步相关推荐
- 疯狂Java学习笔记(69)---------Lock
疯狂Java学习笔记(69)---------Lock Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java ...
- java学习笔记15--多线程编程基础2
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note15.html,转载请注明源地址. 线程的生命周期 1.线程的生命周期 线程从产生到消亡 ...
- java学习笔记14--多线程编程基础1
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为 ...
- 疯狂java学习笔记
<疯狂java>我觉得是一本很好的java基础书,里面解释的比较通俗易懂,不繁琐,深入程度刚刚好,比较适合我现阶段来学习,巩固java基础知识,所以将所做的笔记整理如下: 1.数据类型分类 ...
- 0040 Java学习笔记-多线程-线程run()方法中的异常
run()与异常 不管是Threade还是Runnable的run()方法都没有定义抛出异常,也就是说一条线程内部发生的checked异常,必须也只能在内部用try-catch处理掉,不能往外抛,因为 ...
- 【Java学习笔记】线程学习笔记
一.资源 http://blog.csdn.net/axman/article/details/431796 这个博客里有Java多线程.线程池的一系列,从基础开始就很清楚,牛人 二.重点 今天读到了 ...
- Java学习笔记16-多线程
1.多线程 进程:执行中的程序叫做进程(Process),是一个动态的概念.为了使计算机程序得以运行,计算机需要加载代码,同时也要加载数据,每个进程由3部分组成:cpu,data,co ...
- java学习笔记之线程(一)
线程(一) 一.线程定义于组成: 1.创建任务和线程: 1 TaskThread task = new TaskThread(); // 创建任务 2 Thread taskThread = new ...
- 疯狂java学习笔记之面向对象(二) - 成员变量与局部变量
Java变量按其作用域可分为:成员变量和局部变量.注意:在Java中是没有全局变量这个概念的 一.成员变量: 成员变量是在类中定义的变量,具体可分为类变量与实例变量--有无static修饰 实例变量的 ...
最新文章
- 从业5年,教你学习Linux开发
- 云计算如何帮助直播行业发展
- python软件怎么用-python软件怎么用
- C语言再学习 -- 位、字节、字、字长、字元的关系
- MongoDB配置参数说明
- .NET 6 全新指标 System.Diagnostics.Metrics 介绍
- 纯干货 | UI界面中按钮设计CTA按钮\订阅按钮
- 八年级计算机考操作试题,八年级计算机会考必看试题!!!!!!
- Java面试官:Kafka集群管理
- ❤️区块链Hyperledger Fabric 老版本 1.1.0 快速部署安装 教程合集❤️
- 使用一个运放滤三次谐波 二阶有源带通滤波器的电路设计及波形效果
- adc0809工作过程C语言,ADC0809引脚图、时序图、工作流程图详解
- Solr---string类型的docValues属性、stored属性
- 极限挑战 极致突破——奇安信的2022
- 随身理财专家“挖财”推iPad应用,新增帐号对比功能
- 小学生五星分期,钉钉在线求饶
- 【嵌入式】51单片机+1602+dht11显示温湿度
- 毫米波雷达技术应用,飞睿科技人体存在感应检测模块
- jconsole本地连接失败
- vue 调用webservice_用C#通过反射实现动态调用WebService 告别Web引用(转载)
热门文章
- 深度学习(07)-- 经典CNN网络结构(Inception (v1-v4))
- 《Java8实战》笔记汇总
- Java web后端5 JSP技术
- Android MotionEvent中getX()、getRawX()和getTop()的区别
- .NET技术+25台服务器怎样支撑世界第54大网站
- 广州驾考科目三电子考16日全面启动
- 转载给ffmpeg入门级:我的第一个调用FFmpeg库的程序出炉
- MPEG音视频编解码之MP3编解码概述
- ffmpeg和SDL学习笔记
- jws 方式表格导出,excel文件导出,rest风格接口实现