Java加锁的三种方法总结与案例

文章对比了Java中三种不同的线程同步和通信方式:wait/notify机制,Condition的await/signal接口,以及LockSupport的park/unpark方法。强调了wait和await需要在同步块中调用,而park/unpark不受此限制,且顺序不影响线程的唤醒。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java加锁的三种方法

wait和notify

package com.lockSupport;

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

public class LockSupportTest {
	public static void main(String[] args) {
		test1();
	}

	/**
	 * 测试wait和notify方法
	 */
	public static void test1(){
		Object o = new Object();

		new Thread(()->{
			synchronized (o){
				System.out.println(Thread.currentThread().getName() + "\t ----come in!");
				try {
					o.wait();
				} catch (Exception e){
				    e.printStackTrace();
				}
			}
		}, "t1").start();

		try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

		new Thread(()->{
			synchronized (o){
				o.notify();
				System.out.println(Thread.currentThread().getName() + "\t ---发出通知");
			}
		}, "t2").start();

	}
}

await和signal

package com.lockSupport;

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

/**
 * todo:
 *      1、wait和notify方法
 *      2、Condition的await方法和signal方法
 *      3、LockSupport的park和unpark
 *
 * 结论:一、1和2中的await和wait都需要先加锁再使用,否则报错
 *      二、如果先唤醒再加锁 则会造成线程阻塞,无法被唤醒
 *      三、park和unpark方法则没有上述限制,不加锁也能使用,顺序颠倒也不会影响线程被唤醒
 *
 *
 */
public class LockSupportTest {

	public static void main(String[] args) {
		test3();
	}

	/**
	 * 测试Condition的await方法和signal方法
	 */
	public static void test3(){

		ReentrantLock lock = new ReentrantLock();
		Condition condition = lock.newCondition();

		Thread t1 = new Thread(() -> {

			try {
				lock.lock();
				System.out.println(Thread.currentThread().getName() + "\t ----come in!");
				condition.await();
				System.out.println(Thread.currentThread().getName() + "\t ----被唤醒!");
			} catch (Exception e){
			    e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}, "t1");

		t1.start();

		try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

		new Thread(()->{
			try {
				lock.lock();
				condition.signal();
				System.out.println(Thread.currentThread().getName() + "\t ----发出通知!");
			} catch (Exception e){
			    e.printStackTrace();
			} finally {
			    lock.unlock();
			}
		}, "t2").start();
	}
}



park和unpark

package com.lockSupport;

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

/**
 * todo:
 *      1、wait和notify方法
 *      2、Condition的await方法和signal方法
 *      3、LockSupport的park和unpark
 *
 * 结论:一、1和2中的await和wait都需要先加锁再使用,否则报错
 *      二、如果先唤醒再加锁 则会造成线程阻塞,无法被唤醒
 *      三、park和unpark方法则没有上述限制,不加锁也能使用,顺序颠倒也不会影响线程被唤醒
 *
 *
 */
public class LockSupportTest {

	public static void main(String[] args) {
		//test1();
		//test2();
		test3();

	}

	/**
	 * 测试Condition的await方法和signal方法
	 */
	public static void test3(){

		ReentrantLock lock = new ReentrantLock();
		Condition condition = lock.newCondition();

		Thread t1 = new Thread(() -> {

			try {
				lock.lock();
				System.out.println(Thread.currentThread().getName() + "\t ----come in!");
				condition.await();
				System.out.println(Thread.currentThread().getName() + "\t ----被唤醒!");
			} catch (Exception e){
			    e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}, "t1");

		t1.start();

		try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

		new Thread(()->{

			try {
				lock.lock();
				condition.signal();
				System.out.println(Thread.currentThread().getName() + "\t ----发出通知!");
			} catch (Exception e){
			    e.printStackTrace();
			} finally {
			    lock.unlock();
			}
		}, "t2").start();
	}


	/**
	 * 测试LockSupport的park和unpark功能  这两个方法类似lock和unlock
	 */
	public static void test2(){
		Thread t1 = new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + "\t ----come in!");
			// 线程会阻塞在此处 等待unpark方法执行后才会被唤醒
			LockSupport.park();
			System.out.println(Thread.currentThread().getName() + "\t ----被唤醒!");
		}, "t1");

		t1.start();

		new Thread(()->{
			try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
			LockSupport.unpark(t1);
			System.out.println(Thread.currentThread().getName() + "\t ----发出通知!");
		}, "t2").start();
	}

	

	/**
	 * 测试wait和notify方法
	 */
	public static void test1(){
		Object o = new Object();

		new Thread(()->{
			synchronized (o){
				System.out.println(Thread.currentThread().getName() + "\t ----come in!");
				try {
					o.wait();
				} catch (Exception e){
				    e.printStackTrace();
				}
			}
		}, "t1").start();

		try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

		new Thread(()->{
			synchronized (o){
				o.notify();
				System.out.println(Thread.currentThread().getName() + "\t ---发出通知");
			}
		}, "t2").start();

	}
}

总结

结论:
一、1和2中的await和wait都需要先加锁再使用,否则报错
二、如果先唤醒再加锁 则会造成线程阻塞,无法被唤醒
三、park和unpark方法则没有上述限制,不加锁也能使用,顺序颠倒也不会影响线程被唤醒

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值