Java Lock 怎么用
刚写过一段代码,明明加了“锁”的逻辑,还是出现了数据混乱——相信不少新手写Java多线程代码时,都遇过这种事。其实不是代码写错了,是没搞懂Java里的Lock工具到底怎么用。和大家熟悉的synchronized关键字比,Lock就像个“可定制的门锁”,不是只能简单“锁门”,还能调开门的时间、能不能留缝隙,今天就用生活里的例子讲明白。
第一步:先搞懂“为什么要换Lock”
很多人一开始只会用synchronized,它就像小区大门的门禁,所有人只能在门口排队等保安开,进去后要出来才能让下一个进,虽然安全但太死板。

比如你写一个抢票代码,用synchronized锁整个抢票方法,有人只是想查有没有票,也得等抢票的人出来才能查,效率低到离谱。Lock就不一样了,它可以分“业务锁”——抢票和查票用不同的锁,查票的人不用等抢票,效率直接提上来。
第二步:最基础的Lock用法,像“临时占座”
用Lock的第一步,得先拿个“锁对象”,就像去图书馆占座要先拿号码牌,不能随便拿个本子乱记。
`java
// 1. 先拿锁对象
Lock ticketLock = new ReentrantLock();
// 2. 要锁的时候,先“拿锁”,怕有人走不开还能等
ticketLock.lock();
try {
// 这里是只能一个人做的事,比如改票数
if (ticketCount > 0) {
ticketCount--;
System.out.println("抢票成功,剩余:" + ticketCount);
}
} finally {
// 3. 一定要“还锁”!就像占座走了要把号码牌放回去,不然别人都用不了
ticketLock.unlock();
}
`
这里的finally是关键,哪怕抢票时突然出错(比如用户取消订单),锁也会被还回去,不会卡死所有后续请求——要是忘写finally,就像占座后直接跑路,后面的人全没法用座位。
第三步:解锁“高级功能”,解决常见麻烦
Lock最实用的是两个“定制功能”,新手用一次就会爱上。
第一个是“限时占座”,就像去餐厅吃饭,等位超过10分钟还没位置,直接走,不浪费时间。用代码说就是:
`java
// 最多等3秒拿锁,拿不到就放弃
if (ticketLock.tryLock(3, TimeUnit.SECONDS)) {
try {
// 抢票逻辑
} finally {
ticketLock.unlock();
}
} else {
System.out.println("等太久了,下次再来抢");
}
`
第二个是“公平锁”,比如排队买票,有人不能插在最前面。Lock默认是“非公平锁”(谁先抢到谁用),要改成公平锁很简单,创建Lock时加个参数:
`java
Lock fairLock = new ReentrantLock(true); // 参数true就是公平锁
`
平时写抢票、库存这类场景,用公平锁能避免有人一直抢不到票,更符合实际逻辑。
第四步:避开新手最容易踩的坑
最后说两个一定要注意的点:
第一,绝对不能把lock()放在try外面。要是lock()突然失败,unlock()会报错,整个程序直接崩掉;
第二,别用同一个Lock对象管完全不相关的业务。比如你既用这个锁管抢票,又管查用户信息,相当于把小区大门和单元门用一个锁,单元门的人还得等大门的人开门,太傻了。
其实Java的Lock本质就是把“锁”从关键字变成了一个“工具包”,你可以根据场景选临时锁、公平锁、限时锁,而不是用synchronized的“一刀切”。只要记住“拿锁必还”的核心规则,再结合场景选对应的功能,就能搞定90%的多线程数据混乱问题。