版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Java多线程4:synchronized锁机制一个常见的概念。在多线程中,难免会出现在多个线程中对同一个对象的实例变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是脏读,也就是取到的数据其实是被更改过的。 多线程线程安全问题示例看一段代码:复制代码public class ThreadDomain13 private int num = 0; public void addNum(String userName) try if (a.equals(userName) num = 100; System.out.println(a set over!); Thread.slee
2、p(2000); else num = 200; System.out.println(b set over!); System.out.println(userName + num = + num); catch (InterruptedException e) e.printStackTrace(); 复制代码写两个线程分别去add字符串a和字符串b:复制代码public class MyThread13_0 extends Thread private ThreadDomain13 td; public MyThread13_0(ThreadDomain13 td) this.td =
3、td; public void run() td.addNum(a); 复制代码复制代码public class MyThread13_1 extends Thread private ThreadDomain13 td; public MyThread13_1(ThreadDomain13 td) this.td = td; public void run() td.addNum(b); 复制代码写一个主函数分别运行这两个线程:复制代码public static void main(String args) ThreadDomain13 td = new ThreadDomain13();
4、MyThread13_0 mt0 = new MyThread13_0(td); MyThread13_1 mt1 = new MyThread13_1(td); mt0.start(); mt1.start();复制代码看一下运行结果:a set over!b set over!b num = 200a num = 200按照正常来看应该打印a num = 100和b num = 200才对,现在却打印了b num = 200和a num = 200,这就是线程安全问题。我们可以想一下是怎么会有线程安全的问题的:1、mt0先运行,给num赋值100,然后打印出a set over!,开始睡觉
5、2、mt0在睡觉的时候,mt1运行了,给num赋值200,然后打印出b set over!,然后打印b num = 2003、mt1睡完觉了,由于mt0的num和mt1的num是同一个num,所以mt1把num改为了200了,mt0也没办法,对于它来说,num只能是100,mt0继续运行代码,打印出a num = 200分析了产生问题的原因,解决就很简单了,给addNum(String userName)方法加同步即可:复制代码public class ThreadDomain13 private int num = 0; public synchronized void addNum(Str
6、ing userName) try if (a.equals(userName) num = 100; System.out.println(a set over!); Thread.sleep(2000); else num = 200; System.out.println(b set over!); System.out.println(userName + num = + num); catch (InterruptedException e) e.printStackTrace(); 复制代码看一下运行结果:a set over!a num = 100b set over!b num
7、 = 200 多个对象多个锁在同步的情况下,把main函数内的代码改一下:复制代码public static void main(String args) ThreadDomain13 td0 = new ThreadDomain13(); ThreadDomain13 td1 = new ThreadDomain13(); MyThread13_0 mt0 = new MyThread13_0(td0); MyThread13_1 mt1 = new MyThread13_1(td1); mt0.start(); mt1.start();复制代码看一下运行结果:a set over!b se
8、t over!b num = 200a num = 100打印结果的方式变了,打印的顺序是交叉的,这又是为什么呢?这里有一个重要的概念。关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁,其他线程都只能呈等待状态。但是这有个前提:既然锁叫做对象锁,那么势必和对象相关,所以多个线程访问的必须是同一个对象。如果多个线程访问的是多个对象,那么Java虚拟机就会创建多个锁,就像上面的例子一样,创建了两个ThreadDomain13对象,就产生了2个锁。既然两个线程持有的是不同的锁
9、,自然不会受到等待释放锁这一行为的制约,可以分别运行addNum(String userName)中的代码。 synchronized方法与锁对象上面我们认识了对象锁,对象锁这个概念,比较抽象,确实不太好理解,看一个例子,在一个实体类中定义一个同步方法和一个非同步方法:复制代码public class ThreadDomain14_0 public synchronized void methodA() try System.out.println(Begin methodA, threadName = + Thread.currentThread().getName(); Thread.sl
10、eep(5000); System.out.println(End methodA, threadName = + Thread.currentThread().getName() + , end Time = + System.currentTimeMillis(); catch (InterruptedException e) e.printStackTrace(); public void methodB() try System.out.println(Begin methodB, threadName = + Thread.currentThread().getName() + ,
11、begin time = + System.currentTimeMillis(); Thread.sleep(5000); System.out.println(End methodB, threadName = + Thread.currentThread().getName(); catch (InterruptedException e) e.printStackTrace(); 复制代码一个线程调用其同步方法,一个线程调用其非同步方法:复制代码public class MyThread14_0 extends Thread private ThreadDomain14_0 td; p
12、ublic MyThread14_0(ThreadDomain14_0 td) this.td = td; public void run() td.methodA(); 复制代码复制代码public class MyThread14_1 extends Thread private ThreadDomain14_0 td; public MyThread14_1(ThreadDomain14_0 td) this.td = td; public void run() td.methodB(); 复制代码写一个main函数去掉用这两个线程:复制代码public static void main
13、(String args) ThreadDomain14_0 td = new ThreadDomain14_0(); MyThread14_0 mt0 = new MyThread14_0(td); mt0.setName(A); MyThread14_1 mt1 = new MyThread14_1(td); mt1.setName(B); mt0.start(); mt1.start();复制代码看一下运行效果:Begin methodA, threadName = ABegin methodB, threadName = B, begin time = 1443697780869End
14、 methodB, threadName = BEnd methodA, threadName = A, end Time = 1443697785871从结果看到,第一个线程调用了实体类的methodA()方法,第二个线程完全可以调用实体类的methodB()方法。但是我们把methodB()方法改为同步就不一样了,就不列修改之后的代码了,看一下运行结果:Begin methodA, threadName = AEnd methodA, threadName = A, end Time = 1443697913156Begin methodB, threadName = B, begin t
15、ime = 1443697913156End methodB, threadName = B从这个例子我们得出两个重要结论:1、A线程持有Object对象的Lock锁,B线程可以以异步方式调用Object对象中的非synchronized类型的方法2、A线程持有Object对象的Lock锁,B线程如果在这时调用Object对象中的synchronized类型的方法则需要等待,也就是同步 synchronized锁重入关键字synchronized拥有锁重入的功能。所谓锁重入的意思就是:当一个线程得到一个对象锁后,再次请求此对象锁时时可以再次得到该对象的锁的。看一个例子:复制代码public c
16、lass ThreadDomain16 public synchronized void print1() System.out.println(ThreadDomain16.print1(); print2(); public synchronized void print2() System.out.println(ThreadDomain16.print2(); print3(); public synchronized void print3() System.out.println(ThreadDomain16.print3(); 复制代码复制代码public class MyThr
17、ead16 extends Thread public void run() ThreadDomain16 td = new ThreadDomain16(); td.print1(); 复制代码public static void main(String args) MyThread16 mt = new MyThread16(); mt.start();看一下运行结果:ThreadDomain16.print1()ThreadDomain16.print2()ThreadDomain16.print3()看到可以直接调用ThreadDomain16中的打印语句,这证明了对象可以再次获取自己
18、的内部锁。这种锁重入的机制,也支持在父子类继承的环境中。 异常自动释放锁最后一个知识点是异常。当一个线程执行的代码出现异常时,其所持有的锁会自动释放。模拟的是把一个long型数作为除数,从MAX_VALUE开始递减,直至减为0,从而产生ArithmeticException。看一下例子:复制代码public class ThreadDomain17 public synchronized void testMethod() try System.out.println(Enter ThreadDomain17.testMethod, currentThread = + T currentThr
19、ead().getName(); long l = Integer.MAX_VALUE; while (true) long lo = 2 / l; l-; catch (Exception e) e.printStackTrace(); 复制代码复制代码public class MyThread17 extends Thread private ThreadDomain17 td; public MyThread17(ThreadDomain17 td) this.td = td; public void run() td.testMethod(); 复制代码复制代码public static void main(String args) ThreadDomain17 td = new ThreadDomain17(); MyThread17 mt0 = new MyThread17(td); M
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年度砂石料开采与环境保护合作协议3篇
- 二零二五年度个人消费分期贷款质押担保合同书2篇
- 2025版铁路货运特点与业务流程规范合同3篇
- 香烟店卫生标准规范
- 二零二五年度高校科研成果转化委托实施协议3篇
- 2025版环保设备维修与改造承包协议书2篇
- 二零二五版学生顶岗实习实习单位实习教育与培训合作协议3篇
- 二零二五年大学食堂食品安全保障协议范本3篇
- 二零二五版新风机销售与技术支持合作合同2篇
- 二零二五年度个人二手房交易房屋租赁续约合同
- 2025年病案编码员资格证试题库(含答案)
- 2025新译林版英语七年级下单词表
- 新疆2024年中考数学试卷(含答案)
- 魏宁海超买超卖指标公式
- 2024-2030年中国连续性肾脏替代治疗(CRRT)行业市场发展趋势与前景展望战略分析报告
- (正式版)FZ∕T 80014-2024 洁净室服装 通 用技术规范
- 跨学科主题学习:实施策略、设计要素与评价方式(附案例)
- 场地委托授权
- 剪映专业版:PC端短视频制作(全彩慕课版) 课件 第3章 短视频剪辑快速入门
- 湖南省长沙市开福区青竹湖湘一外国语学校2023-2024学年九年级下学期一模历史试题
- 2024年四川省成都市龙泉驿区中考数学二诊试卷(含答案)
评论
0/150
提交评论