码迷,mamicode.com
首页 > 编程语言 > 详细

Java并发编程-可重入锁

时间:2015-11-09 01:31:39      阅读:370      评论:0      收藏:0      [点我收藏+]

标签:

可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍可以获取该锁而不受影响。
在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁。

[java]public class Test implements Runnable{

public synchronized void get(){
    System.out.println(Thread.currentThread().getId());
    set();
}

public synchronized void set(){
    System.out.println(Thread.currentThread().getId());
}

@Override
public void run() {
    get();
}
public static void main(String[] args) {
    Test ss=new Test();
    new Thread(ss).start();
    new Thread(ss).start();
    new Thread(ss).start();
}
}[/java]

两个例子最后的结果都是正确的,即 同一个线程id被连续输出两次。
结果如下:
Threadid: 8
Threadid: 8
Threadid: 10
Threadid: 10
Threadid: 9
Threadid: 9
可重入锁最大的作用是避免死锁
我们以自旋锁作为例子

[java]public class SpinLock {
    private AtomicReference owner =new AtomicReference<>;
    public void lock(){
        Thread current = Thread.currentThread();
        while(!owner.compareAndSet(null, current)){
        }
    }
    public void unlock (){
         Thread current = Thread.currentThread();
         owner.compareAndSet(current, null);
    }
}[/java]

对于自旋锁来说,
1、若有同一线程两次调用lock() ,会导致第二次调用lock位置进行自旋,产生了死锁
说明这个锁并不是可重入的。(在lock函数内,应验证线程是否为已经获得锁的线程)
2、若1问题已经解决,当unlock()第一次调用时,就已经将锁释放了。实际上不应释放锁。
(采用计数次进行统计)
修改之后,如下:

[java]public class SpinLock1 {
    private AtomicReference owner =new AtomicReference<>;
    private int count =0;
    public void lock(){
        Thread current = Thread.currentThread();
        if(current==owner.get()) {
            count++;
            return ;
        }

        while(!owner.compareAndSet(null, current)){

        }
    }
public void unlock (){
    Thread current = Thread.currentThread();
    if(current==owner.get()){
        if(count!=0){
            count--;
        }else{
            owner.compareAndSet(current, null);
        }

    }

    }
}[/java]

该自旋锁即为可重入锁。

可重入锁机制:每个锁都关联一个请求计数器和一个占有他的线程,当请求计数器为0时,这个锁可以被认为是unhled的,当一个线程请求一个unheld的锁时,JVM记录锁的拥有者,并把锁的请求计数加1,如果同一个线程再次请求这个锁时,请求计数器就会增加,当该线程退出syncronized块时,计数器减1,当计数器为0时,锁被释放。

[java]public class Widget {
public synchronized void doSomething() {
...
}
}

public class LoggingWidget extends Widget {
    public synchronized void doSomething() {
        System.out.println(toString() + ": calling doSomething");
        super.doSomething();
    }
}[/java]

如果没有Java锁的可重入性,当一个线程获取LoggingWidget的doSomething()代码块的锁后,这个线程已经拿到了LoggingWidget的锁,当调用父类中的doSomething()方法的时,JVM会认为这个线程已经获取了LoggingWidget的锁,而不能再次获取,从而无法调用Widget的doSomething()方法,从而造成死锁。从中我们也能看出,java线程是基于“每线程(per-thread)”,而不是基于“每调用的(per-invocation)”的,也就是说java为每个线程分配一个锁,而不是为每次调用分配一个锁。

 

Java并发编程-可重入锁

标签:

原文地址:http://www.cnblogs.com/suxuan/p/4948748.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!