LockSupport基本介绍
LockSupport是JDK1.5中新增的一个类,用于实现线程的阻塞和唤醒。在Java并发编程中,线程的阻塞和唤醒是非常重要的操作,可以通过wait()和notify()方法来实现,但是它们有一定的局限性,比如只能阻塞和唤醒当前线程,并且必须要在synchronized块中执行。而LockSupport则可以弥补这些不足。
LockSupport中的park()和unpark()方法可以分别实现阻塞线程和唤醒线程的功能。和其他的线程控制方法相比,LockSupport有以下优点:
- 可以阻塞和唤醒指定的线程,而不是像wait()和notify()方法一样只能阻塞和唤醒当前线程。
- 不需要获取锁才能操作,而是将操作权限直接分配给调用线程。
- 唤醒操作可以先于阻塞操作,而不像wait()方法只能等待notify()方法的唤醒。
LockSupport使用了一种名为"许可证"(permit)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可证。与Semaphore不同的是,许可证的累加上限是1。permit许可证默认没有不能放行,所以一开始调用park()方法当前线程就会阻塞,直到别的线程给当前线程的发放permit,park方法才会被唤醒。调用unpark(thread)方法后,就会将thread线程的许可证permit发放,会自动唤醒park线程,即之前阻塞中的LockSuppot.pak()方法会立即返回。
LockSupport和其他线程控制方法相比,有以下优势:
- LockSupport可以在任意位置阻塞和唤醒线程,不需要在synchronized块中执行。
- LockSupport可以阻塞和唤醒指定的线程,而不是像wait()和notify()方法一样只能阻塞和唤醒当前线程。
- LockSupport不需要获取锁才能操作,而是将操作权限直接分配给调用线程。
- LockSupport的唤醒操作可以先于阻塞操作,而不像wait()方法只能等待notify()方法的唤醒。
- LockSupport没有死锁的风险,因为它不需要获取锁就可以进行阻塞和唤醒操作。
三种等待唤醒方式
方式1:Object中的wait()和notify()
代码:
代码语言:javascript复制 class WaitNotifyDemo {
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() "进入等待状态");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() "被唤醒,继续执行");
}
}, "线程1");
Thread t2 = new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() "唤醒其他线程");
lock.notify();
}
}, "线程2");
t1.start();
t2.start();
}
}
描述:
wait()和notify()是Object类中的方法,用于实现线程之间的等待和唤醒。当一个线程调用了对象的wait()方法时,该线程会释放对象的锁,并进入等待状态,等待其他线程调用对象的notify()方法将它唤醒;而当一个线程调用了对象的notify()方法时,该对象会随机唤醒一个正在等待它的线程。
在上面的代码中,我们创建了一个共享对象lock,然后启动两个线程t1和t2。t1线程调用了lock的wait()方法进入等待状态,而t2线程调用了lock的notify()方法唤醒t1线程,使其继续执行。
方式2:JUC包中的Condition.await()和signal()
代码:
代码语言:javascript复制 class ConditionDemo {
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() "进入等待状态");
condition.await();
System.out.println(Thread.currentThread().getName() "被唤醒,继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "线程1");
Thread t2 = new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() "唤醒其他线程");
condition.signal();
} finally {
lock.unlock();
}
}, "线程2");
t1.start();
t2.start();
}
}
描述:
Condition是JUC(java.util.concurrent)包中的一个接口,用于实现线程之间的等待和唤醒。相比于Object的wait()和notify()方法,Condition提供了更加灵活的线程控制方式。
在上面的代码中,我们创建了一个共享锁对象lock和一个Condition对象condition。线程t1调用lock的lock()方法获取锁,并调用condition的await()方法进入等待状态;而线程t2调用lock的lock()方法获取锁,并调用condition的signal()方法唤醒线程t1,使其继续执行。
方式3:LockSupport类
代码:
代码语言:javascript复制class LockSupportDemo {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() "进入等待状态");
LockSupport.park();
System.out.println(Thread.currentThread().getName() "被唤醒,继续执行");
}, "线程1");
t1.start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread t2 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() "唤醒其他线程");
LockSupport.unpark(t1);
}, "线程2");
t2.start();
}
}
描述:
LockSupport是JDK1.5中新增的一个类,用于实现线程的阻塞和唤醒。在Java并发编程中,线程的阻塞和唤醒是非常重要的操作,可以通过wait()和notify()方法来实现,但是它们有一定的局限性,比如只能阻塞和唤醒当前线程,并且必须要在synchronized块中执行。而LockSupport则可以弥补这些不足。
在上面的代码中,我们创建了一个线程t1,它调用LockSupport的park()方法进入等待状态,而线程t2调用LockSupport的unpark()方法唤醒线程t1,使其继续执行。