java锁的种类

原创 2017年04月09日 08:34:52

1. 可重入锁

当一个线程重新获取锁,读写锁或其他不可重入的同步器时,就可能发生重入锁死。可重入的意思是线程可以重复获得它已经持有的锁。
Java的synchronized块是可重入的。因此下面的代码是没问题的:

(这里提到的锁都是指的不可重入的锁实现,并不是Java类库中的Lock与ReadWriteLock类)

public class Reentrant{
	public synchronized outer(){
		inner();
	}

	public synchronized inner(){
		//do something
	}
}
注意outer()和inner()都声明为synchronized,这在Java中这相当于synchronized(this)块(注:这里两个方法是实例方法,
synchronized的实例方法相当于在this上加锁,如果是static方法,则不然)。如果某个线程调用了outer(),
outer()中的inner()调用是没问题的,因为两个方法都是在同一个管程对象(即this)上同步的。如果一个线程持有某个管程对象上的锁,
那么它就有权访问所有在该管程对象上同步的块。这就叫可重入。若线程已经持有锁,那么它就可以重复访问所有使用该锁的代码块。
下面这个锁的实现是不可重入的:

public class Lock{
	private boolean isLocked = false;
	public synchronized void lock()
		throws InterruptedException{
		while(isLocked){
			wait();
		}
		isLocked = true;
	}

	public synchronized void unlock(){
		isLocked = false;
		notify();
	}
}
如果一个线程在两次调用lock()间没有调用unlock()方法,那么第二次调用lock()就会被阻塞,这就出现了重入锁死。
我们在上面的Lock基础上作一些修改就会变成可重入的锁(这也是可重入锁的基本原理):

public class Lock{
    boolean isLocked = false;
    Thread  lockedBy = null;
    int lockedCount = 0;
    public synchronized void lock()
        throws InterruptedException{
        Thread callingThread = Thread.currentThread();
        while(isLocked && lockedBy != callingThread){
            wait();
        }
        isLocked = true;
        lockedCount++;
        lockedBy = callingThread;
  }
    public synchronized void unlock(){
        if(Thread.curentThread() == this.lockedBy){
            lockedCount--;
            if(lockedCount == 0){
                isLocked = false;
                notify();
            }
        }
    }
}
lockBy:保存已经获得锁实例的线程,在lock()判断调用lock的线程是否已经获得当前锁实例,如果已经获得锁,则直接跳过while,无需等待。
lockCount:记录同一个线程重复对一个锁对象加锁的次数。否则,一次unlock就会解除所有锁,即使这个锁实例已经加锁多次了。
Java中常用的锁的属性
synchronized:可重入锁;
java.util.concurrent.locks.ReentrantLock:可重入锁;

2.自旋锁

自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区。如下

public class SpinLock {

  private AtomicReference<Thread> sign =new AtomicReference<>();

  public void lock(){
    Thread current = Thread.currentThread();
    while(!sign .compareAndSet(null, current)){
    }
  }

  public void unlock (){
    Thread current = Thread.currentThread();
    sign .compareAndSet(current, null);
  }
}
使用了CAS原子操作,lock函数将owner设置为当前线程,并且预测原来的值为空。unlock函数将owner设置为null,并且预测值为当前线程。
当有第二个线程调用lock操作时由于owner值不为空,导致循环一直被执行,直至第一个线程调用unlock函数将owner设置为null,
第二个线程才能进入临界区。由于自旋锁只是将当前线程不停地执行循环体,不进行线程状态的改变,所以响应速度更快。
但当线程数不停增加时,性能下降明显,因为每个线程都需要执行,占用CPU时间。
如果线程竞争不激烈,并且保持锁的时间段。适合使用自旋锁。

参考:
http://ifeve.com/reentrance-lockout/
http://ifeve.com/java_lock_see1/
http://www.jianshu.com/p/007bd7029faf


版权声明:本文为博主整理自网络资料,转载请注明!

相关文章推荐

java锁的种类以及辨析

转载自: http://ifeve.com/java_lock_see1/  锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLoc...

java锁的种类以及辨析

锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) 。这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及...

java锁的种类以及辨析

java锁的种类以及辨析(一):自旋锁 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) 。这些已经写好提供的...

java锁的种类及研究

Java锁的种类以及辨析 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) 。这些已经写好提供的锁为我们开发提...

Java菜鸟面试突破系列之事物方方面面(事物种类特性及隔离级别、悲观锁和乐观锁等)

数据库事物的方方面面(包含特性及隔离级别、悲观锁和乐观锁等)纲要:本篇文章主要汇总网络上关于这方面的总结以应对校招,哈哈哈,介绍数据库事物相关的方方面面,从事物谈起,提及事物的特性、隔离级别、以及数据...

java 锁的类型和性质(二):自旋锁的其它种类

package lock; import java.util.concurrent.atomic.AtomicInteger; public class TicketLock { private At...
  • luairan
  • luairan
  • 2014年09月11日 22:18
  • 507

Java锁的种类以及辨析(三):阻塞锁

锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) 。这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类...

java锁的种类以及辨析(一):自旋锁

java锁的种类以及辨析(一):自旋锁 作者:山鸡 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 )...
  • fwt336
  • fwt336
  • 2017年02月09日 17:13
  • 177

java锁的种类之读写锁

转自:http://ifeve.com/read-write-locks/#simple  原文链接作者:Jakob Jenkov 译者:微凉 校对:丁一 相比Java中的锁(Locks ...
  • Hnkuo
  • Hnkuo
  • 2016年05月01日 00:59
  • 792
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java锁的种类
举报原因:
原因补充:

(最多只允许输入30个字)