微科社区,轻松开发从此开始! 请登陆 免费注册

微科社区

当前位置:首页 > Java平台 > 多线程编程 >

线程安全与锁优化

时间:2017-01-19 04:01  浏览:努力统计中...
Brian Goetz对线程安全的定义:当多个线程访问一个对象时,如果不考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调度方进行任何其他的协调操作,

        Brian Goetz对线程安全的定义:当多个线程访问一个对象时,如果不考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调度方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的

        并发处理的广泛应用是使得Amdahl定律替代摩尔定律成为计算机性能发展源动力,是人类压榨计算机运算能力最有力的武器

        线程安全 限定为多个线程之间存在共享数据访问。因为如果多个线程之间不存在共享数据的话,那么从线程安全的角度看,程序串行和多线程执行时完全没有区别的。

       java里面安全程度由强到弱排序(也是由Brian Goetz提出的):不可变,绝对线程安全,相对线程安全,线程兼容,线程对立

       不可变:可以是基本类型的final;可以是final对象,但对象的行为不会对其状态产生任何影响,比如String的subString就是new一个String对象 各种Number类型如BigInteger和BigDecimal等大数据类型都是不可变的,但是同为Number子类型的AtomicInteger和AtomicLong则并非不可变我觉得原因是它里面状态对象时unsafe对象,所做的操作都是CAS操作,可以保证原子性。

       绝对线程安全:他是完全满足Brian Goetz给出的线程安全的定义,一个类要达到这种程度,需要付出很大的,甚至不切实际的代价。

java里面很多看上去非常安全的类,比如vector其实也不能满足这一点。例子:
线程A
for(int i=0; i<vectoe.size();i++) {
vector.remove(i);
}
线程B
for(int i=0; i<vectoe.size();i++) {
vector.get(i);
}
会报ArrayIndexOutOfBoundsException。
需要额外的同步
线程A
synchronized{
for(int i=0; i<vectoe.size();i++) {
vector.remove(i);
}
}
线程B
synchronized{
for(int i=0; i<vectoe.size();i++) {
vector.get(i);
}
}

相对线程安全:这就是我们通常意义上的线程安全。需要保证对象单独的操作时线程安全的。

比如vector,hashtable,synchronizedCollection包装集合

线程兼容:对象本身不是线程安全的,但可以通过同步手段实现。一般我们说的不是线程安全的,绝大多数是指这个。
比如ArrayList,HashMap等

线程对立:不管调用端是否采用了同步的措施,都无法在并发中使用的代码。

调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。

线程安全的实现

1、互斥同步

在多线程访问的时候,保证同一时间只有一条线程使用。
临界区(Critical Section),互斥量(Mutex),信号量(Semaphore)都是同步的一种手段
java里最基本的互斥同步手段是synchronized,编译之后会形成monitorenter和monitorexit这两个字节码指令,这两个字节码都需要一个reference类型的参数来指明要锁定和解锁的对象(可以通过工具读class文件,这是以后必须要做的),还有个锁的计数器,来记录拥有锁的次数,跟AQS里面的state一样
其实在“Java与线程”里已经提到,java的线程是映射到操作系统的原生线程之上的,不管阻塞还是唤醒都需要操作系统的帮忙完成,都需要从用户态转换到核心态,这是很耗费时间的,是java语言中的一个重量级(Heavyweight)操作,虽然虚拟机本身会做一点优化的操作,比如通知操作系统阻塞之前会加一段自旋等待的过程,避免频繁切换到核心态。
ReentrantLock也是一个很好的选择。
1)ReentrantLock比synchronized增加了一些高级的功能
2)从性能角度考虑,在JDk1.5时代,多线程环境下synchronized的吞吐量下降得非常严重,而ReentrantLock则能保持在比较稳定的水平线上,但是从1.6开始两者性能上基本持平。所以现在这个理由已经不再是了。
虚拟机未来一定是向原生的synchronized改进,所以提倡在synchronized能实现需求的情况下,优先考虑synchronized
2、非阻塞同步
互斥和同步最主要的问题就是阻塞和唤醒所带来的性能问题,所以这通常叫阻塞同步(悲观的并发策略)
随着硬件指令集的发展,我们有另外的选择:基于冲突检测的乐观并发策略,通俗讲就是先操作,如果没有其他线程争用共享的数据,操作就成功,如果有,则进行其他的补偿(最常见就是不断的重试),这种乐观的并发策略许多实现都不需要把线程挂起

顶一下
(0)
0%
踩一下
(0)
0%
------分隔线------
栏目列表
推荐内容