2.synchronized锁和Lock锁
1、Lock锁
传统synchronized锁
开发中多线程实现
/*
资源类oop
* */
class Ticket {
private int num = 100;
//synchronized 本质:队列 锁
public synchronized void sale() {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "卖出第" + (num--) + "张票,剩余" + num + "张票");
}
}
}
/*
真正的多线程开发
线程就是一个单独的资源类,没有任何附属的操作
1.属性 2.方法 oop编程
* */
public class SaleTicket {
public static void main(String[] args) {
//并发:多个线程操作同一个资源类
Ticket ticket = new Ticket();
new Thread(()->{
for (int i = 1; i <= 150; i++) {
ticket.sale();
}
},"a").start();
new Thread(()->{
for (int i = 1; i <= 150; i++) {
ticket.sale();
}
},"b").start();
new Thread(()->{
for (int i = 1; i <= 150; i++) {
ticket.sale();
}
},"c").start();
}
}
Lock接口
加锁解锁
Lock l = ...; l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
实现类
-
ReentrantLock 可重入锁(常用)
-
ReentrantReadWriteLock.ReadLock 读锁
-
ReentrantReadWriteLock.WriteLock 写锁
-
公平锁:十分公平,可以先来后到,必须排队
-
非公平锁:十分不公平,可以插队(默认)
/*
资源类oop
* */
class Ticket01 {
private int num = 100;
/*
构造方法:
1.无参时,是非公平锁NonfairSync()
2.有参时(boolean),true:公平锁FairSync(),false:非公平锁
* */
Lock lock = new ReentrantLock();
public void sale() {
lock.lock();//加锁
try {//业务代码
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "卖出第" + (num--) + "张票,剩余" + num + "张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();//解锁
}
}
}
synchronized锁和lock锁区别
-
synchronized是关键字,lock是java类
-
synchronized无法判断获取锁的状态,lock可以判断是否获取到了锁
-
synchronized会自动释放锁,lock锁必须手动释放,不释放会死锁
-
synchronized 线程1(获得锁,阻塞) 线程2(傻傻的等);lock锁不一定会等待
lock.tryLock();//尝试获取锁
-
synchronized 可重入锁,不可以中断,非公平;lock,可重入锁,可以判断锁,可以自己设置公平或非公平
-
synchronized适合锁少量代码同步问题,lock适合锁大量的同步代码
2、生产者和消费者
2.1、传统synchronized方式
- 等待:wait
- 唤醒:notify notifyAll
两个线程时,if不会出问题
/*
* 一个线程num+1,一个线程num-1
* */
public class A {
public static void main(String[] args) {
Date date = new Date();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "a").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "b").start();
}
}
class Date {
private int num = 0;
//+1
public synchronized void increment() throws InterruptedException {
if (num != 0) {
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName() + "+==>" + num);
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
if (num == 0) {
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName() + "-==>" + num);
this.notifyAll();
}
}
3,4个线程时,用if时,不符合判断条件的话就等待,唤醒后是直接顺着wait后面的代码继续执行的,不会再判断
而用了while,唤醒之后会重新判断循环条件
改为while就可以
2.2、JUC方式
-
锁:Lock
-
等待: await(Condition类下)
-
唤醒:signal(Condition类下)
/*
* 一个线程num+1,一个线程num-1,
* */
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* > 3,4个线程时,用if时,不符合判断条件的话就等待,唤醒后是直接顺着wait后面的代码继续执行的,不会再判断
> 而用了while,唤醒之后会重新判断循环条件
改为*/
public class A {
public static void main(String[] args) {
//Data data = new Data();
JucData data = new JucData();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "a").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "b").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "c").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "d").start();
}
}
//juc方式
class JucDate {
private int num = 0;
Lock lock = new ReentrantLock();//声明锁
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
lock.lock();//加锁
try {
while (num != 0) {
condition.await();//等待
}
num++;
System.out.println(Thread.currentThread().getName() + "+==>" + num);
condition.signalAll();//唤醒
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();//释放锁
}
}
public void decrement() throws InterruptedException {
lock.lock();
try {
while (num == 0) {
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName() + "-==>" + num);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
目前为止:synchronized和juc方式实现,多个线程执行是无序的。所以condition优势就来了,可以精准通知和唤醒线程
2.3、Conditin精准通知和唤醒
public class ConditionTest {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printA();
}
},"a").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printB();
}
},"b").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printC();
}
},"c").start();
}
}
/*
* 需求:线程A,B,C顺序调用
* num=1:A,2:B,3:C
* */
class Data {
private int num = 1;
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void printA() {
lock.lock();
try {
while (num != 1) {
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"==>AAA");
num = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (num != 2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"==>BBB");
num = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (num != 3) {
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"==>CCC");
num = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY