Java 中的Lock锁

Lock锁,可以得到和 synchronized一样的效果,即实现原子性、有序性和可见性。

相较于synchronized,Lock锁可手动获取锁和释放锁、可中断的获取锁、超时获取锁。

Lock 是一个接口,两个直接实现类:ReentrantLock(重入锁), ReentrantReadWriteLock(读写锁)。

1. 概述

Lock锁,使用时手动获取锁和释放锁,比synchronized更加灵活;可中断的获取锁;超时获取锁。

Lock 锁的基本用法, l.lock()方法进行上锁, l.unlock()方法进行解锁,如下所示。

 Lock l = ...;
 l.lock(); // 上锁
 try {
   // access the resource protected by this lock
 } finally {
   l.unlock(); // 解锁
 }

2. Lock锁的API

修饰符和类型方法描述
voidlock()获得锁。
voidlockInterruptibly​()获得锁,可中断。举个例子,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。
booleantryLock​()锁在空闲的才能获取锁(未获得锁不会等待)。举个例子:当两个线程同时通过lock.trylock()想获取某个锁时,假若此时线程A获取到了锁,而线程B不会等待,直接放弃获取锁。
booleantryLock​(long time, TimeUnit unit)

如果锁定可用,则此方法立即返回值true

如果锁不可用,则当前线程将被禁用以进行线程调度,并且在发生以下三种情况之一之前处于休眠状态:

  • 当前线程获取锁。
  • 其他一些线程中断当前线程。
  • 等待时间过去了,返回false
voidunlock​()释放锁。

3. lock() 方法,unlock()方法

创建一个 Lock 锁:

Lock l = new ReentrantLock();

给代码块上锁:

        l.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": ");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        l.unlock();

全部代码:

package lock;

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

public class MyLockStudy implements Runnable {

    private int count;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        l.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": ");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        l.unlock();
    }

    public static void main(String args[]) {
        MyLockStudy runn = new MyLockStudy();
        Thread thread1 = new Thread(runn, "thread1");
        Thread thread2 = new Thread(runn, "thread2");
        Thread thread3 = new Thread(runn, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行截图:

4. tryLock()方法

tryLock​(),锁在空闲的才能获取锁(未获得锁不会等待,lock()未获得锁会进入阻塞状态 ),返回值为boolean类型,获取锁则为 true ,反之为 false。

tryLock() 进行加锁:

        if (l.tryLock()) {
            System.out.println(Thread.currentThread().getName() + "获取锁");
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + ": ");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            l.unlock();
        } else {
            System.out.println(Thread.currentThread().getName() + "未获取锁");
        }

完整代码: 

package lock;

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

public class MyLockStudy implements Runnable {

    private int count;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        if (l.tryLock()) {
            System.out.println(Thread.currentThread().getName() + "获取锁");
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + ": ");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            l.unlock();
        } else {
            System.out.println(Thread.currentThread().getName() + "未获取锁");
        }

    }

    public static void main(String args[]) {
        MyLockStudy runn = new MyLockStudy();
        Thread thread1 = new Thread(runn, "thread1");
        Thread thread2 = new Thread(runn, "thread2");
        Thread thread3 = new Thread(runn, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行截图如下所示:

5. tryLock​(long time, TimeUnit unit) 方法

如果锁定可用,则此方法立即返回值true。如果锁不可用,则当前线程将被禁用以进行线程调度,并且在发生以下三种情况之一之前处于休眠状态:

  • 当前线程获取锁。
  • 其他一些线程中断当前线程。
  • 等待时间过去了,返回false

设置等待时间为 1000 毫秒。

        try {
            if (l.tryLock(1000, TimeUnit.MILLISECONDS)) {
                System.out.println(Thread.currentThread().getName() + "获取锁");
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + ": ");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                l.unlock();
            } else {
                System.out.println(Thread.currentThread().getName() + "未获取锁");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

完整代码如下所示:

package lock;

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

public class MyLockStudy implements Runnable {

    private int count;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        try {
            if (l.tryLock(1000, TimeUnit.MILLISECONDS)) {
                System.out.println(Thread.currentThread().getName() + "获取锁");
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + ": ");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                l.unlock();
            } else {
                System.out.println(Thread.currentThread().getName() + "未获取锁");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public static void main(String args[]) {
        MyLockStudy runn = new MyLockStudy();
        Thread thread1 = new Thread(runn, "thread1");
        Thread thread2 = new Thread(runn, "thread2");
        Thread thread3 = new Thread(runn, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行截图:

如果锁不可用,则当前线程将被禁用以进行线程调度,并且在发生以下三种情况之一之前处于休眠状态,当前线程是可以被中断的。

package lock;

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

public class MyLockStudy implements Runnable {

    private int count;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        try {
            if (l.tryLock(1000, TimeUnit.MILLISECONDS)) {
                System.out.println(Thread.currentThread().getName() + "获取锁");
                for (int i = 0; i <= 500000000; i++) {
                    if (i == 500000000) {
                        System.out.println("运算结束");
                    }
                }
                l.unlock();
            } else {
                System.out.println(Thread.currentThread().getName() + "未获取锁");
            }
        } catch (InterruptedException e) {
            System.out.println("中断");
            e.printStackTrace();
        }

    }

    public static void main(String args[]) {
        MyLockStudy runn = new MyLockStudy();
        Thread thread1 = new Thread(runn, "thread1");
        Thread thread2 = new Thread(runn, "thread2");
        Thread thread3 = new Thread(runn, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread1.interrupt();
        thread2.interrupt();
        thread3.interrupt();
    }
}

线程1获取了锁,其他线程休眠,然后被中断。 

 

  • 14
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java 的 tryLock 方法可以用来实现自旋。tryLock 方法尝试获取,如果获取成功,则立即返回 true,否则返回 false。可以在循环调用 tryLock,直到成功获取为止。这样就可以实现自旋的效果。 例如: ``` Lock lock = new ReentrantLock(); while(!lock.tryLock()){ //do something } try{ //critical section }finally{ lock.unlock(); } ``` 这样做的缺点是会占用CPU资源,如果竞争激烈的话会导致性能问题。 ### 回答2: Java的tryLock()方法是java.util.concurrent.locks.ReentrantLock的一个方法,用于实现自旋。自旋是一种基于循环的,当线程尝试获取时,如果发现已被其他线程持有,则不会进入等待状态,而是通过循环不断尝试获取,直到获取成功为止。 tryLock()方法可以尝试获取,如果当前没有被其他线程持有,则获取成功并返回true;如果已被其他线程持有,则获取失败,并立即返回false,不会阻塞线程。使用该方法可以避免线程进入等待状态,减少线程切换的开销,提高程序的执行效率。 tryLock()方法还提供了重载方法,可以设置超时时间,在限定的时间内尝试获取。如果超过指定的时间仍未获取到,则放弃获取,返回false。通过设置超时时间,可以防止线程长时间等待,避免可能的死情况发生。 自旋在某些场景下可以提高程序的性能,特别是对于的竞争不激烈、持有的时间较短的情况。但是在一些高并发场景下,长时间的自旋可能会消耗大量的CPU资源,导致程序性能下降。因此,需要根据具体的业务场景来选择合适的机制。 综上所述,Java的tryLock()方法实现了自旋,通过不断尝试获取而不进入等待状态,提高了程序的执行效率。但是需要注意在高并发场景下的使用,避免长时间的自旋带来的性能问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值