Lock锁接口(JUC vital)

实现类

  • ReentrantLock(可重入锁)
  • ReentrantReadWriteLock.ReadLock
  • ReentrantReadWriteLock.WriteLock

底层扩展

  • FairSync():公平锁,先来后到
  • NonfairSync(default mechanism):非公平锁,可以插队
//源码:构造方法
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

使用步骤

  • 1.Lock lock = new ReentrantLock();
  • 2.lock.lock();//加锁
  • 3.lock.unlock();//解锁
  • 代码示例:
package com.cyl.demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SafeTicketDemo02 {
    public static void main(String[] args) {
        //并发,多线程同时操作一个资源类,将资源类丢入线程
        Ticket02 ticket = new Ticket02();
        //@FunctionInterface 函数式接口
        // jdk1.8之后使用lambda表达式简化书写:(parameter)->{code}
        new Thread(()->{
            for (int i = 0; i < 20; i++) ticket.sale();
        },"a0").start();
        new Thread(()->{
            for (int i = 0; i < 20; i++) ticket.sale();
        },"a1").start();
        new Thread(()->{
            for (int i = 0; i < 20; i++) ticket.sale();
        },"a2").start();
    }
}
//资源类
//Lock锁
class Ticket02{
    // 1.属性,方法(OOP思想)
    private int ticketNums = 20;
    Lock lock = new ReentrantLock();
    //卖票的方法
    public void sale() {
        lock.lock();//加锁
        try {//业务代码
            if (ticketNums > 0) {
                System.out.println(Thread.currentThread().getName()+
                        "卖出了"+(ticketNums--)+"张票,剩余"+ticketNums);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//解锁
        }
    }
}

##Synchronized与Lock锁的区别

  • 1.Synchronized是Java内置的关键字,Lock是Java的一个应用类
  • 2.Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁
  • 3.Synchronized会自动释放锁,Lock需要手动解锁,如果不释放锁,会出现死锁现象
  • 4.Synchronized线程b在等待线程a释放锁时,恰好线程a发生阻塞,那么线程b会一直等下去;而Lock锁不一定继续等待,会通过lock.tryLock()方法尝试获取锁
  • 5.Synchronized是可重入,非公平锁,不可以中断;Lock是可重入锁,可对锁的状态进行判断,非公平(可以自定义)
  • 6.Synchronized适合锁少量的代码同步问题;Lock适合锁大量的同步代码
//源码:构造方法
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

问题重述:生产者和消费者的问题

package com.cyl.PC;
/**
 * 线程之间的通信问题(线程交替执行),等待唤醒,通知唤醒
 * 单例模式,生产者和消费者,死锁
 * A对num进行+1,告诉B之后,B对num进行-1
 * */
public class A {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
    }
}
//判断是否需要等待,业务,通知
class Data { //数字,资源类
    private int num = 0;
    //+1
    public synchronized void increment() throws InterruptedException {
        if (num != 0) {
            //等待
            this.wait();
        }
        num ++ ;
        System.out.println(Thread.currentThread().getName()+"==>"+num);
        //通知其他线程,我+1执行结束了
        this.notifyAll();
    }
    //+2
    public synchronized void decrement() throws InterruptedException {
        if (num == 0) {
            //等待
            this.wait();
        }
        num -- ;
        System.out.println(Thread.currentThread().getName()+"==>"+num);
        //通知其他线程,我-1执行结束了
        this.notifyAll();
    }
}
那假设线程变得更多呢?(A,B,C,D…)

线程变多,即就产生了虚假唤醒问题,将if判断改为while循环判断即可。

生产者和消费者问题(JUC解决)

  • 传统版本:Synchronized wait notify
  • JUC版本:Lock await signal
  • 代码实现:
class Data02 { //数字,资源类
    private int num = 0;
    Lock lock = new ReentrantLock();
    //condition:精准通知和唤醒线程
    Condition condition = lock.newCondition();
    public void decrement() throws InterruptedException {
        try {
            lock.lock();
            //业务代码
            while (num == 0) {
                //等待
                condition.await();
            }
            //通知其他线程
            condition.signalAll();
        }catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
  • 线程间实现顺序通信
package com.cyl.PC;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 线程间通信,实现顺序执行
 * A执行完之后通知B,B执行完之后通知C,C执行完通知A
 */
public class C {
    public static void main(String[] args) {
        Data03 data = new Data03();
        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();
    }
}
//资源类
class Data03 {//Lock
    private Lock lock = new ReentrantLock();
    Condition condition01 = lock.newCondition();//同步监视器
    Condition condition02 = lock.newCondition();
    Condition condition03 = lock.newCondition();
    private int num = 1;//1A 2B 3C
    public void printA() {
        lock.lock();
        try {//业务代码->判断->执行->通知
            while(num != 1) {
                //等待
                condition01.await();
            }
            System.out.println(Thread.currentThread().getName()+"AA");
            //唤醒指定的线程(B)
            num = 2;
            condition02.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printB() {
        lock.lock();
        try {//业务代码->判断->执行->通知
            while(num != 2) {
                condition02.await();
            }
            System.out.println(Thread.currentThread().getName()+"BB");
            num = 3;
            condition03.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printC() {
        lock.lock();
        try {//业务代码->判断->执行->通知
            while (num != 3) {
                condition03.await();
            }
            System.out.println(Thread.currentThread().getName()+"CC");
            num = 1;
            condition01.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}