java 可重入锁、自旋锁、可中断锁、公平锁、 读写锁

可重入锁

可重入锁,指的是同一线程 外层方法获得之后 调用了仍然需要获取同一个锁的方法,不用重新获取,可以直接执行。在JAVA中synchronized和ReentrantLock 都是 可重入锁。

可重入锁最大的作用是避免死锁

代码示例1:

public class MyRunnable implements Runnable{

	public synchronized void fun1(){
		System.out.println(Thread.currentThread().getName());
		fun2();
	}

	public synchronized void fun2(){
		System.out.println(Thread.currentThread().getName());
	}

	@Override
	public void run() {
		fun1();
	}
	public static void main(String[] args) {
		MyRunnable mr = new MyRunnable();
		new Thread(mr).start();
		new Thread(mr).start();
		new Thread(mr).start();
	}
}

代码示例2:

ublic class MyRunnable implements Runnable {
	ReentrantLock lock = new ReentrantLock();

	public void fun1() {
		lock.lock();
		System.out.println(Thread.currentThread().getName());
		fun2();
		lock.unlock();
	}

	public void fun2() {
		lock.lock();
		System.out.println(Thread.currentThread().getName());
		lock.unlock();
	}

	@Override
	public void run() {
		fun1();
	}

	public static void main(String[] args) {
		MyRunnable mr = new MyRunnable();
		new Thread(mr).start();
		new Thread(mr).start();
		new Thread(mr).start();
	}
}

可重入自旋锁

在获取不到锁的情况下,会让当前线程一直做空循环,避免进入阻塞状态

public class SpinLock {
    private AtomicReference<Thread> owner =new AtomicReference<>();
    private int count =0;
    // 获取锁
    public void lock(){
        Thread current = Thread.currentThread();
        // 为了避免不可重入,在lock的时候需要判断操作的是否是同一线程
        // 同一线程,多次调用lock,计数 +
        if(current==owner.get()) {
            count++;
            return ;
        }
        // CAS不成功,空循环
        while(!owner.compareAndSet(null, current)){
        }
        // 执行到这里,就表示获取到锁了
    }
    
    // 释放锁
    public void unlock (){
        Thread current = Thread.currentThread();
        if(current==owner.get()){
        // 同一线程,多次调用unlock,计数归零后,才能将锁释放掉
            if(count!=0){
                count--;
            }else{
                owner.compareAndSet(current, null);
            }
        }
    }
}

可中断锁

如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,线程B不想等待,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。

在Java中,synchronized不是可中断锁,而Lock是可中断锁。

Lock#lockInterruptibly()与Lock#lock()方法(待获取锁成功后,才响应中断。)不同,
优先考虑响应中断,再去获取锁。

   /**
     * 获取锁,除非线程被打断。
     * 如果锁不被其他线程持有,则获取锁,并立即返回,将锁持有计数设置为1。
     * 如果当前线程已经持有此锁,那么持有计数将增加1,方法立即返回。
     * 如果锁被另一个线程持有,那么当前线程将出于线程调度的目的被禁用,
     * 并处于休眠状态,直到发生以下两种情况之一:
     * 1.锁由当前线程获取。
     * 2.其他线程打断当前线程。
     * 如果锁被当前线程获取,那么锁持有计数被设置为1。
     *
     * 如果当前线程:进入此方法时,其中断状态是否已设置
     * 或者当获取锁时被打断
     * 则会抛出InterruptedException,并清除interrupted status。
     *
     * 在这个实现中,由于这个方法是一个显式的中断点,
     * 所以优先响应中断而不是正常的或可重入的锁获取。
     *
     * @throws InterruptedException if the current thread is interrupted
     */
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    
    /**
     * 以独占模式获取,如果中断将中止。
     * 首先检查中断状态,然后至少调用一次{@link #tryAcquire},成功后返回。
     * 否则,线程将排队,可能反复阻塞和解除阻塞,调用{@link #tryAcquire},直到成功或线程被中断。
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     * @throws InterruptedException if the current thread is interrupted
     */
    public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }

公平锁

尽量按照请求顺序来获取锁。比如同时有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。非公平锁即无法保证锁的获取是按照请求锁的顺序进行的。这样就可能导致某个或者一些线程永远获取不到锁。在Java中,synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。而对于ReentrantLock和ReentrantReadWriteLock,它默认情况下是非公平锁,但是可以设置为公平锁。

/**
 * 如果参数为true表示为公平锁,为fasle为非公平锁。
 * 默认情况下,如果使用无参构造器,则是非公平锁。
**/
ReentrantLock lock = new ReentrantLock(true);

读写锁

对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。可以通过readLock()获取读锁,通过writeLock()获取写锁。


更多锁的只是

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值