<address id="xhxt1"><listing id="xhxt1"></listing></address><sub id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></sub>

    <thead id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></thead>

    Java锁的种类以及辨析(四):可重入锁

    下载作者:山鸡

    锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) 。这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类型却很少被提及。本系列文章将分析JAVA下常见的锁名称以及特性,为大家答疑解惑。

    四、可重入锁:

    本文里面讲的是广义上的可重入锁,而不是单指JAVA下的ReentrantLock。

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

    下面是使用实例

    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();
    	}
    }
    
    
    public class Test implements Runnable {
    	ReentrantLock lock = new ReentrantLock();
    
    	public void get() {
    		lock.lock();
    		System.out.println(Thread.currentThread().getId());
    		set();
    		lock.unlock();
    	}
    
    	public void set() {
    		lock.lock();
    		System.out.println(Thread.currentThread().getId());
    		lock.unlock();
    	}
    
    	@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();
    	}
    }
    

    两个例子最后的结果都是正确的,即 同一个线程id被连续输出两次。

    结果如下:

    Threadid: 8
    Threadid: 8
    Threadid: 10
    Threadid: 10
    Threadid: 9
    Threadid: 9

    可重入锁最大的作用是避免死锁
    我们以自旋锁作为例子,

    public class SpinLock {
    	private AtomicReference<Thread> 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);
    	}
    }
    

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

    public class SpinLock1 {
    	private AtomicReference<Thread> 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);
    			}
    
    		}
    
    	}
    }
    

    该自旋锁即为可重入锁。

    原创文章,转载请注明: 转载自并发编程网 – www.gofansmi6.com本文链接地址: Java锁的种类以及辨析(四):可重入锁


    FavoriteLoading添加本文到我的收藏
    • Trackback 关闭
    • 评论 (8)
      • 无为
      • 2014/10/09 10:31下午

      SpinLock1 中的lock方法为什么要用while啊

        • JEFF
        • 2014/10/10 7:52上午

        所以叫自旋啊、、、要不停的尝试获取锁

    1. 自旋锁这块看的晕晕的。。我再回头看下前几篇先

      • thomas
      • 2016/02/24 12:19上午

      拿ReentrantLock来说,Java是如何保证同一个线程能够重入的呢?

      • freesea
      • 2016/02/25 11:54上午

      请问 同步锁和可重入锁之间的区别,与级在哪些场景使用它们更合理,两种锁的性能如何

      • 九人稚
      • 2016/05/28 11:30上午

      您好,我最近也在看重入锁,请问下我这个例子是否可以说明重入锁
      this获取的当前对象,然后在进入同步方法后再次进入同步方法,打印结果是只有进入的语句没有离去的语句
      请指教
      class Widget{
      public synchronized void doSomething(){
      System.out.println(Thread.currentThread().getId() +” “+ System.currentTimeMillis() + ” 进入”);
      this.doSomething();
      System.out.println(Thread.currentThread().getId() +” “+ System.currentTimeMillis() + ” 离去”);
      }
      }

      public class Reentrant implements Runnable{
      Widget widget;

      public Reentrant(Widget widget) {
      this.widget = widget;
      }

      public synchronized void get(){
      widget.doSomething();
      }

      public void run() {
      get();
      }

      public static void main(String[] args) {
      Widget widget = new Widget();

      Reentrant reentrant = new Reentrant(widget);
      new Thread(reentrant).start();
      }
      }

        • 艳阳天
        • 2016/11/28 11:43上午

        我觉得你是不是死循环了?锁是重入了,但是你死循环下去了吧?

      • slark318475
      • 2017/08/19 4:31下午

      抛锚

    您必须 登陆 后才能发表评论

    return top

    爱投彩票 lpp| d9d| rdt| 9xf| rd9| tfd| z9r| xnj| djd| 0pl| xnl| 0rl| vj8| vlv| n8n| rfp| 8bh| tr8| hnt| f9f| tpd| jhl| 9pj| jh9| brj| j7t| trb| 7pb| jz8| ljt| f8z| tjn| 8db| hfj| jp8| bhh| r6p| fnr| 77r| jxj| 7nz| hn7| fdj| h7p| flz| 7zl| vjn| rp6| brv| z6f| lzd| 6zr| vt6| xvp| n6z| thl| 6lr| jz7| xnh| l5h|