根据你的需求,我将补充完整的内容以及代码运行结果。
继续内容:
Lock 接口中的 tryLock(long time, TimeUnit unit)
方法是可以实现超时等待的。也就是说,如果线程在获取锁时未能在指定的时间内获取锁,它可以选择放弃等待或进行其他操作。这个方法本身并不可中断,但可以通过线程调用 Thread.interrupt()
方法中断当前线程。
而 lockInterruptibly()
方法才是真正的 可中断锁,它允许线程在等待锁时响应中断。当一个线程在等待锁的时候,如果它被中断,那么它会抛出 InterruptedException
并允许线程根据需要处理这个异常。
下面是通过两个示例展示这两种锁的不同:
示例 1:使用 tryLock(long time, TimeUnit unit)
实现超时等待
tryLock()
方法会尝试在指定的时间内获取锁,如果成功则继续执行任务。如果在规定的时间内没有获取到锁,线程会放弃等待并执行其他操作。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
public class TryLockDemo {
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
// 启动第一个线程
Thread thread1 = new Thread(new Task("Thread-1"));
thread1.start();
// 启动第二个线程
Thread thread2 = new Thread(new Task("Thread-2"));
thread2.start();
// 主线程稍等 1 秒后尝试中断线程2
Thread.sleep(1000);
thread2.interrupt(); // 中断线程2
}
static class Task implements Runnable {
private String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
// 使用 tryLock 尝试获取锁,最多等待 2 秒
if (lock.tryLock(2, TimeUnit.SECONDS)) {
try {
System.out.println(name + " 获取锁成功!");
// 模拟任务执行
Thread.sleep(3000); // 模拟执行时间
} catch (InterruptedException e) {
System.out.println(name + " 被中断!");
} finally {
lock.unlock(); // 释放锁
}
} else {
System.out.println(name + " 获取锁超时!");
}
} catch (InterruptedException e) {
System.out.println(name + " 线程被中断!");
}
}
}
}
示例 2:使用 lockInterruptibly()
响应中断
lockInterruptibly()
方法在获取锁时会响应中断。如果在等待锁期间线程被中断,它会抛出 InterruptedException
并允许线程处理该异常。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockInterruptiblyDemo {
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
// 启动第一个线程
Thread thread1 = new Thread(new Task("Thread-1"));
thread1.start();
// 启动第二个线程
Thread thread2 = new Thread(new Task("Thread-2"));
thread2.start();
// 主线程稍等 1 秒后尝试中断线程2
Thread.sleep(1000);
thread2.interrupt(); // 中断线程2
}
static class Task implements Runnable {
private String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
// 使用 lockInterruptibly 来响应中断
lock.lockInterruptibly();
try {
System.out.println(name + " 获取锁成功!");
// 模拟任务执行
Thread.sleep(3000); // 模拟执行时间
} catch (InterruptedException e) {
System.out.println(name + " 被中断!");
} finally {
lock.unlock(); // 释放锁
}
} catch (InterruptedException e) {
System.out.println(name + " 线程被中断!");
}
}
}
}
注意:
- 当 线程1 调用
lock.lockInterruptibly()
时,线程1会尝试获取锁。如果此时锁被其他线程(例如线程2)持有,线程1会进入 等待 状态。 - 如果在等待锁的过程中没有被中断,线程1会成功获取锁,然后继续执行
System.out.println(name + " 获取锁成功!");
,并且开始执行模拟的任务(Thread.sleep(3000)
)。
代码运行结果
示例 1 (tryLock
):
Thread-1 获取锁成功!
Thread-2 获取锁超时!
在此示例中,线程 Thread-1
获取到了锁,线程 Thread-2
尝试获取锁,但是由于 tryLock
设置了超时时间,它最终没有获取到锁并超时。
示例 2 (lockInterruptibly
):
Thread-1 获取锁成功!
Thread-2 线程被中断!
在此示例中,线程 Thread-1
获取到了锁并执行任务,而线程 Thread-2
在 1 秒后被中断,它的获取锁操作被中断并捕获到 InterruptedException
,所以输出 "Thread-2 线程被中断!"。
如果代码处 thread2.interrupt(); 改成thread1.interrupt() 中断线程1 ,那么结果是:
Thread-1 线程被中断!
Thread-2 获取锁成功!
总结:
-
tryLock(long time, TimeUnit unit)
: 适合在希望给线程一个时间限制来获取锁的场景。如果没有在规定的时间内获取到锁,线程会放弃并执行其他操作。它 不可中断,即使线程被中断,锁尝试依然会继续进行直到超时。 -
lockInterruptibly()
: 在获取锁时会响应中断。如果线程在等待锁期间被中断,它会抛出InterruptedException
,从而可以在中断发生时提前退出或进行其他处理。适用于需要在等待锁时响应中断的场景。 -
lockInterruptibly()
适用于那些需要在长时间等待锁时能中断并执行清理或响应其他事件的场景。它可以有效防止线程无限期地阻塞,尤其适合需要灵活中断控制的任务,比如线程池的任务、长时间的 I/O 操作、死锁预防、响应外部事件等。
这两个方法各自有不同的应用场景,取决于线程需要如何响应中断或是否需要超时控制。