死锁和活锁以及各种锁机制的比较


    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)使用某种决策机制。(例如公平性)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值