赞
踩
synchroniezd 同步锁时一种互拆锁。主要通过同步方法或者同步块的形式来使用同步锁。 同步锁的优点是形式简单,易于理解和使用。但是同步锁依赖于隐藏在对象后的内置监视器,比较抽象,不怎么直观。
ReetrantLock和ReentrantReadWriteLock 可重入锁和读写锁。 可重入锁是一中互斥锁,它和同步锁具有相同的基本行为和语义,但是在同步锁在同步锁的基础上扩展了很多的功能,如非阻塞加锁操作、在尝试获取锁时可中断、测试锁是否可持有、
锁的获取顺序等。
读写锁除了提供可重入锁的一些特性外,还包含自己的一些特性,它把锁分为读锁和写锁,多个线程可以同时获取读锁,相对于其他两种互斥锁,读写锁允许更大程度上的并发。读写锁的选取与读的频率、读写操作的持续时间及正在读写的线程数有关。
StampedLock 邮戳锁。邮戳锁提供了多种模式供选择,他不像可重入锁和读写锁实现了Lock接口,但比较而言, 读模式(特别是乐观读模式)允许更大程度上的并发。
在具体的使用中了,还得参考各自的使用场景,并不是同步锁synchronized的性能就不好。
锁的不足之处:
在多核时代,锁的竞争会影响共享内存并行程序的性能性能。由于临界资源的竞争,处理器的多个处理核只有一个处理核处于运行状态,其他的处理核都处于空闲状态,从而导致程序的串行执行,运行效率差,并损害了程序的可伸缩性。
解决方案,使用STM(软件事务型内存) 优点是可以使程序的并行度达到最大。缺点是开销大,容易导致活锁。(这个我不是很理解,需要深入理解?????????)
减少锁竞争的方法:
1)减少锁的持有时间,只对共享区域的数据加锁,对不是共享的数据操作去除锁。
2)减少对锁的请求频率。
3)通过锁分解等手段降低锁的粒度,使用细粒度的锁。
4)使用高性能的同步控制方式。
死锁
死锁是指两个或者两个以上的线程在执行的过程中,因竞资源而相互等待的现象。处于死锁状态的各个线程无法继续运行,只有死锁解锁才能进行。
代码示例:
public class Data{
int a =0;
int b =0;
String str = "Data";
public synchronized void increase(){
synchronized(str){
a++;
b++;
}
}
public void isEquals(){
synchronized(str){
synchronized(this){
System.out.println("a="+a+"\tb="+b+"\t"+(a==b) );
}
}
}
}
public class Worker implements Runnable(){
private Data data;
public Worker(Data data){
this.data = data;
}
public void run(){
data.increase();
}
}
public class Index{
public static void main(String [] args ){
Data data = new Data();
Worker worker1 = new Worker(data);
Worker worker2 = new Worker(data);
Thread t1 = new Thread(worker1);
Thread t2 = new Thread(worker2);
t1.start();
t2.start();
while(true){
data.isEquals();
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
分析:该程序中,对于increase()方法使用了两次加锁,但两次加锁使用的监视对象不同,对于方法修饰的中的synchronized使用当前对象this作为监视对象,对于同步块中的synchronized使用的是自定义的String对象作为监视对象,二者各自加锁是不影响。
程序在运行过程中,方法main()作为主线程是和两个线程一起执行了,当线程启动,t1调用了方法increase(),t1首先尝试对this对象加锁,如果线程没锁,怎么t1对this加锁成功,此时主线程main调用了isEquals()方法,尝试使用对象加锁,如果str没有加锁,
则主线程多str加锁成功。此后,线程t1尝试对str加锁,由于str已经被主线程main加锁,则线程t1等待;主线程main尝试对this加锁,则发现this已经被线程t1加锁,则main线程等待;线程t2调用increase(),尝试对this加锁,this对象已经被t1加锁,怎么
线程t2等待,此时。三个线程都在等待其他线程释放自己需要的锁。程序无法继续执行,就造成了死锁。
造成死锁的主要原因:
1)线程的相互等待;
2)线程的互不相让;
3)请求资源不可用;
4)线程的永久阻塞;
5)死循环。
避免的死锁的方法:
1)避免在临界区域循环嵌套
2)顺序访问资源
3)减少临界区的颗粒粒度
4)允许线程被打断
活锁:
活锁是指在程序执行过程中,由于某些条件(如:其他任务抢占了该任务的cpu执行),会导致程序一直处于等待状态,无法运行,也叫饿死线程。
解决活锁的方法:
1)引入随机性。
2)使用某种决策机制。(例如公平性)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。