您当前的位置: 首页 > 

Dongguo丶

暂无认证

  • 3浏览

    0关注

    472博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Lock接口

Dongguo丶 发布时间:2021-09-16 09:00:42 ,浏览量:3

什么是Lock

Lock锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对象。Lock提供了比synchronized更多的功能。实现比synchronized更细粒度的加锁操作

Lock与的Synchronized区别

1Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;

2Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

3 Lock可以让等待锁的线程响应中断interrupted(),而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;.

4通过Lock可以知道有没有成功获取锁tryLock(),而synchronized却无法办到。

5 Lock可以提高多个线程进行读操作的效率。在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争) ,此时Lock的性能要远远优于synchronized.

Lock接口
public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}
lock()

lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。

采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。

newCondition()

关键字synchronized与wait()/notify()这两个方法一起使用可以实现等待/通知模式, Lock锁的newContition()方法返回Condition对象,Condition类也可以实现等待/通知模式。

用notify()通知时,JVM会随机唤醒某个等待的线程, 使用Condition类可以进行选择性通知, Condition比较常用的两个方法:

• await()会使当前线程等待,同时会释放锁,当其他线程调用signal()时,线程会重新获得锁并继续执行。

• signal()用于唤醒一个等待的线程。

注意:在调用Condition的await()/signal()方法前,也需要线程持有相关的Lock锁,调用await()后线程会释放这个锁,在singal()调用后会从当前Condition对象的等待队列中,唤醒 一个线程,唤醒的线程尝试获得锁, 一旦获得锁成功就继续执行。

image-20210903104315229

ReentrantLock

ReentrantLock,意思是“可重入锁”,

ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法。

ReentrantLock可打断

如果希望等待的状态可以被打断就可以使用lockInterruptibly()

如果是可中断模式,那么可以使用 interrupt 让等待中断

public void lockInterruptibly() throws InterruptedException {
    this.sync.acquireInterruptibly(1);
}
package com.dongguo.sync;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Dongguo
 * @date 2021/9/12 0012-14:59
 * @description:
 */
public class LockInterruptiblyDemo {
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            try {
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("等待锁的过程中被打断");
                return;
            }
            try {
                System.out.println(Thread.currentThread().getName()+"获得了锁");
            } finally {
                lock.unlock();
            }
        }, "t1");

        lock.lock();
        System.out.println(Thread.currentThread().getName()+"获得了锁");

        t1.start();

        try {
            TimeUnit.SECONDS.sleep(1);
            System.out.println(Thread.currentThread().getName()+"中断t1等待");
            t1.interrupt();//中断等待
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
运行结果
main获得了锁
main中断t1等待
等待锁的过程中被打断
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at com.dongguo.sync.LockInterruptiblyDemo.lambda$main$0(LockInterruptiblyDemo.java:17)
	at java.lang.Thread.run(Thread.java:748)
ReentrantLock锁超时
public boolean tryLock() {
    return this.sync.nonfairTryAcquire(1);
}

public boolean tryLock(long var1, TimeUnit var3) throws InterruptedException {
    return this.sync.tryAcquireNanos(1, var3.toNanos(var1));
}
立刻失败
package com.dongguo.sync;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Dongguo
 * @date 2021/9/12 0012-15:42
 * @description:
 */
public class TimeOutLockDemo {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            if (!lock.tryLock()) {
                System.out.println(Thread.currentThread().getName() + "获取不到立刻失败,返回");
                return;
            }
            try {
                System.out.println(Thread.currentThread().getName() + "获得了锁");
            } finally {
                lock.unlock();
            }
        }, "t1");
        lock.lock();
        System.out.println(Thread.currentThread().getName() + "获得了锁");
        t1.start();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
运行结果
main获得了锁
t1获取不到立刻失败,返回
超时失败
package com.dongguo.sync;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Dongguo
 * @date 2021/9/12 0012-15:42
 * @description:
 */
public class TimeOutLockDemo {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            try {
                if (!lock.tryLock(1,TimeUnit.SECONDS)) {
                    System.out.println(Thread.currentThread().getName() + "获取不到等待1s后失败,返回");
                    return;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                System.out.println(Thread.currentThread().getName() + "获得了锁");
            } finally {
                lock.unlock();
            }
        }, "t1");
        lock.lock();
        System.out.println(Thread.currentThread().getName() + "获得了锁");
        t1.start();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
运行结果
main获得了锁
t1获取不到立刻失败,返回
ReentrantLock条件变量

synchronized 中也有条件变量,就是monitor的 waitSet 休息室,当条件不满足时进入 waitSet 等待 ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比 synchronized 是那些不满足条件的线程都在一间休息室等消息 而 ReentrantLock 支持多间休息室,比如有专门等烟的休息室、专门等早餐的休息室、唤醒时也是按休息室来唤 醒 使用要点: await 前需要获得锁 await 执行后,会释放锁,进入 conditionObject 等待 await 的线程被唤醒(或打断、或超时)取重新竞争 lock 锁 竞争 lock 锁成功后,从 await 后继续执行

实例:

使用了线程间定制化通信的例子

A线程打印2次A,B线程打印3次B,C线程打印5次C,按照此顺序循环10轮

思路:创建三个线程给每个线程设置一个标志位

线程A判断flag=0,打印2次,修改flag=1,通知线程B

线程B判断flag=1,打印3次,修改flag=2,通知线程C

线程C判断flag=2,打印5次,修改flag=0,通知线程A

package com.dongguo.concurrent.lock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Dongguo
 * @date 2021/9/3 0003-15:01
 * @description:
 */
public class ThreadOrderAccessDemo {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        new Thread(() -> {
            for (int i = 1; i  {
            for (int i = 1; i  {
            for (int i = 1; i             
关注
打赏
1638062488
查看更多评论
0.0402s