本文为多线程第一篇,java
不深刻细节,数据库
大致上聊一聊咱们经常使用的类,安全
先来一张图感觉下:多线程
在上面三组类中,开发时咱们大都是使用的上面的,如使用StringBuilder作String拼接。 使用ArrayList存储数据库返回的一组数据, 用HashMap传参等等。app
由于如今开发大都是在SpringMVC下开发,全局变量都是一些Manager, Service,Mapper之类的。 而后咱们的List, Map变量通常都是在方法里面新建,使用,返回。在jvm中,局部变量存在于vm栈的每一个方法的栈帧中,这个线程所私有的,不会引起线程安全问题,因此咱们用上面的或是下面的程度大均可以正确的运行,也正是这样,也让咱们一直没有机会深刻到他们之中,看看他们有什么不同jvm
StringBuilder VS StringBuffer , 对比方法 append()ide
ArrayList VS Vector , 对比方法 add()学习
HashMap VS Hashtable , 对比方法 put() ui
细心的小伙伴们估计已经注意到了,线程
两个类的这些方法中,
方法名,参数,返回值,
和实现都大致上差很少,
只是在方法声明上有些差异:
synchronized.synchronized放在非static方法是,
是对当前实例加锁,
例:
Hashtable<String,String> table = new Hashtable<>();
table.put("java","技术大本营");
table.get("java");
咱们在使用table 这个实例时,线程A要使用table的get方法,就要先等别的线程使用完put方法。这种读写相间的说是为了保证数据一致加个锁倒也无可厚非,可是,若是两个线程都是使用get方法,也是同一时间只有一个线程能读取。因此如今在项目中不多看到后Vector 和 hashtable出现了。
从平常开发中,咱们不难总结出,读 实际上是不须要加锁的,只有写的时候才须要加锁,并且写的时候也不至于从方法第一行就加锁,能够只对更改的那几行加锁就能够了,或者对数据分段,对须要修改的那一段数据加锁。 总体的思路就是,下降锁的粒度。 还有更厉害的就是直接不加锁了,你们一块儿去竞争,但改以前必需要和本身之前拿到的数据对比,中间没有人动过才能改。
相信已经有小伙伴经过上段的描述想到了对应的例子,如ConcurrentHashMap , CAS等等 , 这些是后话,今天先和你们一块儿认识一些孪生的线程(不)安全的类。
总结:一般一提到线程安全,你们都会第一时间想到加锁,但对谁加锁,何时加锁,是个值得考量的问题!