博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java多线程4:synchronized锁机制
阅读量:5861 次
发布时间:2019-06-19

本文共 1515 字,大约阅读时间需要 5 分钟。

脏读

一个常见的概念。在多线程中,难免会出现在多个线程中对同一个对象的实例变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数据其实是被更改过的。

 

 

 

按照正常来看应该打印"a num = 100"和"b num = 200"才对,现在却打印了"b num = 200"和"a num = 200",这就是线程安全问题。我们可以想一下是怎么会有线程安全的问题的:

1、mt0先运行,给num赋值100,然后打印出"a set over!",开始睡觉

2、mt0在睡觉的时候,mt1运行了,给num赋值200,然后打印出"b set over!",然后打印"b num = 200"

3、mt1睡完觉了,由于mt0的num和mt1的num是同一个num,所以mt1把num改为了200了,mt0也没办法,对于它来说,num只能是100,mt0继续运行代码,打印出"a num = 200"

分析了产生问题的原因,解决就很简单了,给addNum(String userName)方法加同步即可:

 

打印结果的方式变了,打印的顺序是交叉的,这又是为什么呢?

这里有一个重要的概念。关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁,其他线程都只能呈等待状态。但是这有个前提:既然锁叫做对象锁,那么势必和对象相关,所以多个线程访问的必须是同一个对象

如果多个线程访问的是多个对象,那么Java虚拟机就会创建多个锁,就像上面的例子一样,创建了两个ThreadDomain13对象,就产生了2个锁。既然两个线程持有的是不同的锁,自然不会受到"等待释放锁"这一行为的制约,可以分别运行addNum(String userName)中的代码。

 

 

synchronized方法与锁对象

 

 

从结果看到,第一个线程调用了实体类的methodA()方法,第二个线程完全可以调用实体类的methodB()方法。但是我们把methodB()方法改为同步就不一样了,就不列修改之后的代码了,看一下运行结果:

 

 

从这个例子我们得出两个重要结论:

1、A线程持有Object对象的Lock锁,B线程可以以异步方式调用Object对象中的非synchronized类型的方法

2、A线程持有Object对象的Lock锁,B线程如果在这时调用Object对象中的synchronized类型的方法则需要等待,也就是同步

 

synchronized锁重入

关键字synchronized拥有锁重入的功能。所谓锁重入的意思就是:当一个线程得到一个对象锁后,再次请求此对象锁时时可以再次得到该对象的锁。看一个例子:

看到可以直接调用ThreadDomain16中的打印语句,这证明了对象可以再次获取自己的内部锁。这种锁重入的机制,也支持在父子类继承的环境中

 

 

异常自动释放锁

最后一个知识点是异常。当一个线程执行的代码出现异常时,其所持有的锁会自动释放。模拟的是把一个long型数作为除数,从MAX_VALUE开始递减,直至减为0,从而产生ArithmeticException。看一下例子:

因为打印结果是静态的,所以不是很明显。在l--前一句加上Thread.sleep(1)结论会更明显,第一句打出来之后,整个程序都停住了,直到Thread-0抛出异常后,Thread-1才可以运行,这也证明了我们的结论。

 

 

转载于:https://www.cnblogs.com/doudouxiaoye/p/5792850.html

你可能感兴趣的文章
Redis 集合和有序集合
查看>>
http请求头与响应头的应用
查看>>
零基础学习 Python 之列表
查看>>
使用leancloud实现迭代查询
查看>>
事件循环(the Event Loop)、宏任务(macrotask)、微任务(microtask)
查看>>
apply call bind 简介
查看>>
iOS Deep Linkin 和 Deferred Deep Linking
查看>>
如何定制一个下拉框
查看>>
顺丰删库工程师遭开除,难道他不会恢复误删数据?
查看>>
二叉搜索树(Binary Search Tree)
查看>>
Java工程师如何在1个月内做好面试准备?
查看>>
安卓绿色联盟最强联名,超百家应用/企业共贺新春
查看>>
学习webpack4 - 第三方库的使用
查看>>
【跃迁之路】【730天】程序员高效学习方法论探索系列(实验阶段487-2019.2.20)...
查看>>
The Rise of Worse Is Better 论文-学习笔记
查看>>
使用 Docker 部署 Spring Boot项目
查看>>
【技术性】Search知识
查看>>
leetcode389.Find The Difference
查看>>
java中具有继承关系的类及其对象初始化顺序
查看>>
linux上ssh免密登录原理及实现
查看>>