试着简单易懂记录synchronized this object Class的区别,模拟ConcurrentHashMap
修饰静态方法默认获取当前class的锁,同步方法没有释放的锁,不影响class其他非同步方法的调用,也不影响不同锁的同步方法,更不影响使用class的其他属性.
package thread.base.sync; import java.util.concurrent.TimeUnit; /**
*
* @author ZhenWeiLai
*
*/
public class A { synchronized public static void saySomething() throws InterruptedException{
//前后可以写非同步代码
synchronized(A.class){
System.out.println("a");
TimeUnit.SECONDS.sleep(5);
}
//前后可以写非同步代码
} // /**
// * 与上面相等(但是方法内没有非同步区域):可以这么理解,把synchronized当修饰符用总不能写成synchronized(A.claa) public static void saySomething()
// * 这是静态方法啊,不需要实例就可以调用,那么我获取什么锁啊?只能获取本class的锁吖,你又不能给我传参
// */
// synchronized public static void saySomething() throws InterruptedException{
// System.out.println("a");
// TimeUnit.SECONDS.sleep(5);
// }
}
修饰非静态方法,默认获取调用此方法的实例对象锁 Spring容器管理的bean默认都是单例的(当然可以注解为prototype),所以加上 synchronized 的方法,注解自动装配获取的实例,调用都会同步了
package thread.base.sync; import java.util.concurrent.TimeUnit; /**
*
* @author ZhenWeiLai
*
*/
public class A { public void saySomething() throws InterruptedException {
//前面可以写非同步代码
synchronized (this) {
System.out.println("a");
TimeUnit.SECONDS.sleep(5);
}
//后面可以写非同步代码
} // /**
// * 与上面相等,看了静态的,再看对象方法更好理解.
// * 必须要有实例才能调用吧?太好办了那么我就获取当前实例对象的锁
// */
// synchronized public void saySomething() throws InterruptedException{
// System.out.println("a");
// TimeUnit.SECONDS.sleep(5);
// }
}
synchronized (object)与synchronized (this)一样,获取实例对象的锁.因为synchronized (this)只能获取当前实例锁,那么synchronized (object)就是可以获取其他实例锁的意思
对于synchronized 最简单粗暴的理解就是,你要哪些线程方法同步,就跟他们获取一样的锁好了,A.class,就获取A.class, objectA 就获取 objectA(我说的不是对象名相同,而是真真切切在java堆中的同一个对象),
据说ConcurrentHashMap 就是用16个对象锁实现的
我也模拟一下
package thread.base.sync.hashmap; import java.util.HashMap;
import java.util.concurrent.TimeUnit; /**
*
* @author ZhenWeiLai 模拟16个并发的线程安全put
* @param <K>
* @param <V>
*/
public class SyncHashMap<K, V> extends HashMap<K, V> {
/**
*
*/
private static final long serialVersionUID = 4071859310703431745L; // 初始化16个对象锁
Object[] lock = new Object[16]; public SyncHashMap() {
for (int i = 0; i < 16; i++) {
lock[i] = new Object();
}
} /**
* 线程安全方法
*
* @param key
* @param value
* @return
* @throws InterruptedException
*/
public V safePut(K key, V value) throws InterruptedException {
/**
* 不一样的key有可能得到一样的余数,据说hashcode算法问题.我这里是取巧,不深究
* 万一两个不同的key得到一样的余数,那么慢的一个就要等待5秒咯
* 随机获取16个对象锁中的一个
*/
synchronized (lock[key.hashCode() % 16]) {
System.out.println("aaaa");
TimeUnit.SECONDS.sleep(5);
// 同步调用原生put方法
return super.put(key, value);
}
} }
测试方法,两个key相同,其中获取锁慢的那个线程会等5秒再输出控制台
package thread.base.sync.hashmap; /**
*
* @author ZhenWeiLai
*
*/
public class TestClass {
public static void main(String[] args) {
SyncHashMap<Integer,Integer> shm = new SyncHashMap<>();
new Thread(()->{
try {
//两个线程操作同一个key,
shm.safePut(1, 1);
} catch (Exception e) {
e.printStackTrace();
}
}).start(); new Thread(()->{
try {
//两个线程操作同一个key
shm.safePut(1,1);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
试着简单易懂记录synchronized this object Class的区别,模拟ConcurrentHashMap的更多相关文章
- HashSet的实现原理,简单易懂
HashSet的实现原理,简单易懂 答: HashSet实际上是一个HashMap实例,都是一个存放链表的数组.它不保证存储元素的迭代顺序:此类允许使用null元素.HashSet中不允许有重复元 ...
- 如果简单的记录,就可以为这个世界创造更多的财富,那么还有什么理由不去写博客呢? — 读<<黑客与画家>> 有感
上一次博文发文时间是2016.1.15,7个月已经过去了.最近读了一本<>的书,对我触动挺大的!里面有关于技术趋势的探讨,也有关于人生和财富的思考! 开始更新iOS122的文章的初衷是,聚 ...
- Python简单爬虫记录
为了避免自己忘了Python的爬虫相关知识和流程,下面简单的记录一下爬虫的基本要求和编程问题!! 简单了解了一下,爬虫的方法很多,我简单的使用了已经做好的库requests来获取网页信息和Beauti ...
- redis5.0.3单实例简单安装记录
redis5.0.3单实例简单安装记录 日常需要测试使用,索性记录下来,免得临时又麻烦的找资料. yum -y install make gcc-c++ cmake bison-devel ncurs ...
- 【repost】让你一句话理解闭包(简单易懂)
接触javascript很久了,每次理解闭包都似是而非,最近在找Web前端的工作,所以需要把基础夯实一下. 本文是参照了joy_lee的博客 闭包 在她这篇博客的基础上以批注的形式力争把我的理解阐述出 ...
- 5、Cocos2dx 3.0游戏开发找小三之測试例子简单介绍及小结
重开发人员的劳动成果.转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27186557 測试例子简单介绍 Cocos2d-x ...
- Oracle触发器简单入门记录
写在前面: 最近,老项目新增了日报优化的需求,丽姐让我用触发器去实现当数据插入或者更新的时候,实现对日报表数据更新操作.嗯嗯嗯呢,之前学习数据库的时候,有碰到过触发器,但都是一跳而过,也没怎么去真正的 ...
- 27:简单错误记录SimpleErrorLog
题目描述 开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号. 处理: 1. 记录最多8条错误记录,循环记录,对相同的错误记录(净文件名称和行号完全匹配)只记录一条,错误计数增加: ...
- 【转】JS回调函数--简单易懂有实例
JS回调函数--简单易懂有实例 初学js的时候,被回调函数搞得很晕,现在回过头来总结一下什么是回调函数. 我们先来看看回调的英文定义:A callback is a function that is ...
随机推荐
- Log4j源码解析--LoggerRepository和Configurator解析
本文转自上善若水的博客,原文出处:http://www.blogjava.net/DLevin/archive/2012/07/10/382678.html.感谢作者的无私分享. LoggerRepo ...
- JAVA中JPA的主键自增长注解设置
JPA的注解来定义实体的时候,使用@Id来注解主键属性即可.如果数据库主键是自增长的,需要在增加一个注解@GeneratedValue,即: @GeneratedValue(strategy=Gene ...
- Linux 修改环境变量报错
报错如下: -bash: export: `=': not a valid identifier -bash: export: `/usr/local/sbin:/usr/local/bin:/sbi ...
- SQL模板资源管理器,你用了吗?
SQL Server Management Studio 有个模板资源管理器,不知你用过没有?使用模板创建脚本.自定义模板等功能能大大提高你的工作效率,如果没有尝试过,赶紧去试试吧.很多时候,我们习惯 ...
- jsp的语法
JSP指令和脚本元素指令 <%@ 指令%>声明 <%! 声明%>表达式 <%= 表达式%>代码段/脚本段 <% 代码段%>注释 <%-- 注释-- ...
- sed标签
转载 b label ,无条件跳转到标签label,如果label没有指定,跳转到命令的结尾 t label ,如果最后一次输入的最后一个 s/// 子命令执行成功,跳转到标签label,如果labe ...
- 字段的参数 -- Django从入门到精通系列教程
该系列教程系个人原创,并完整发布在个人官网刘江的博客和教程 所有转载本文者,需在顶部显著位置注明原作者及www.liujiangblog.com官网地址. Python及Django学习QQ群:453 ...
- JAVA设计模式---命令模式
1.定义: 将“请求”封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象,命令模式也支持可撤销的操作.命令可以用来实现日志和事务系统. 2.实例: 1)需求:设计一个家电遥控器的API,遥控 ...
- 解决Bug:Size of a request header field exceeds server limit
用了cms 发现这玩意真不好,老是有各种奇芭的问题跳出来 有时浏览网页时会出现 Bad Request Your browser sent a request that this server cou ...
- 济南清北学堂游记 Day 2.
在大佬云集的地方被直线碾压是什么样的体验? 大概就是210和1030的差别. 大概就是高质量机械键盘和空气的区别. 回来的路上,我一直在想,我到底是不是一个高三的? 大概也是能找到以前在家和学校训练时 ...