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锁区别

  1. synchronized是关键字,lock是java类

  2. synchronized无法判断获取锁的状态,lock可以判断是否获取到了锁

  3. synchronized会自动释放锁,lock锁必须手动释放,不释放会死锁

  4. synchronized 线程1(获得锁,阻塞) 线程2(傻傻的等);lock锁不一定会等待

    lock.tryLock();//尝试获取锁
    
  5. synchronized 可重入锁,不可以中断,非公平;lock,可重入锁,可以判断锁,可以自己设置公平或非公平

  6. 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();
        }
    }
}
posted @   jpy  阅读(5)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· 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
点击右上角即可分享
微信分享提示