JUC——Lock接口

目录

  • Lock是什么
  • Lock接口的实现: ReentrantLock可重入锁
  • Lock实现线程间通信(生产者消费者)
  • 线程间定制化通信
  • Lock与Syncronize的区别

Lock是什么

锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对象。
JUC——Lock接口_第1张图片

Lock接口的实现: ReentrantLock可重入锁

使用模板:

class X {
     
   private final ReentrantLock lock = new ReentrantLock();
   // ...
 
   public void m() {
     
     lock.lock();  // block until condition holds
     try {
     
       // ... method body
     } finally {
     
       lock.unlock()
     }
   }
 }

示例:

public class SaleTicket {
     
    /**
     * 三个售票员  卖出    30张票
     *
     * @param args
     * @throws Exception 线程 操作 资源类,高内聚低耦合
     */
    public static void main(String[] args) throws Exception {
     
        Ticket ticket = new Ticket();

        new Thread(()->{
     for (int i = 1; i <= 40; i++) ticket.sale(); },"A售票员").start();
        new Thread(()->{
     for (int i = 1; i <= 40; i++) ticket.sale(); },"B售票员").start();
        new Thread(()->{
     for (int i = 1; i <= 40; i++) ticket.sale(); },"C售票员").start();

    }
}
class Ticket {
     
    private int number = 30;
    private Lock lock = new ReentrantLock();

    public void sale() {
     
        lock.lock();
        try {
     
            if (number > 0) {
     
                System.out.println(Thread.currentThread().getName()
                        + "\t 卖出" + number-- + "号票\t还剩" + number
                );
            }
        } catch (Exception e) {
     
            e.printStackTrace();
        } finally {
     
            lock.unlock();
        }
    }
}

Lock实现线程间通信(生产者消费者)

JUC——Lock接口_第2张图片
JUC——Lock接口_第3张图片

 private Lock lock = new ReentrantLock();//获取锁
 private Condition cd = lock.newCondition();//获取钥匙

生产者消费者:

class ShareDataOne {
     
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition cd = lock.newCondition();

    public  void incr() throws InterruptedException {
     
        lock.lock();
        try {
     
            //判断
            while  (number != 0) {
     
                cd.await();
            }
            //干活
            number++;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            //通知
            cd.signalAll();
        } catch (Exception e) {
     
            e.printStackTrace();
        } finally {
     
            lock.unlock();
        }
    }
    public  void decr() throws InterruptedException {
     
        lock.lock();
        try {
     
            //判断
            while  (number != 1) {
     
                cd.await();
            }
            //干活
            number--;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            //通知
            cd.signalAll();
        } catch (Exception e) {
     
            e.printStackTrace();
        } finally {
     
            lock.unlock();
        }
    }
}
/**
 * 现在两个线程
 * 操作一个初始值为0的变量
 * 实现一个线程对变量增加1,一个线程对变量减少1
 * 交替,来10轮
 * 、线程 操作 资源类 2、高内聚低耦合
 * 1、判断
 * 2、干活
 * 3、通知
 *
 * 注意多线程之间的虚假唤醒
 */
public class NotifyWaitDemo {
     
    public static void main(String[] args) {
     
        ShareDataOne shareDataOne = new ShareDataOne();
        new Thread(() -> {
     
            for (int i = 1; i <= 10; i++) {
     
                try {
     
                    shareDataOne.incr();
                } catch (InterruptedException e) {
     
                    e.printStackTrace();
                }
            }
        }, "AA").start();
        new Thread(() -> {
     
            for (int i = 1; i <= 10; i++) {
     
                try {
     
                    shareDataOne.decr();
                } catch (InterruptedException e) {
     
                    e.printStackTrace();
                }
            }
        }, "BB").start();
        new Thread(() -> {
     
            for (int i = 1; i <= 10; i++) {
     
                try {
     
                    shareDataOne.incr();
                } catch (InterruptedException e) {
     
                    e.printStackTrace();
                }
            }
        }, "CC").start();
        new Thread(() -> {
     
            for (int i = 1; i <= 10; i++) {
     
                try {
     
                    shareDataOne.decr();
                } catch (InterruptedException e) {
     
                    e.printStackTrace();
                }
            }
        }, "DD").start();
    }
}

线程间定制化通信

引入:多线程之间按顺序调用,实现A->B->C
三个线程启动,要求如下:
AA打印5次,BB打印10次,CC打印15次
接着
AA打印5次,BB打印10次,CC打印15次
…来10轮

class ShareData{
     

    private  int num = 1;//标志判断位:1:AA,2:BB,3:CC

    private Lock lock = new ReentrantLock();
    Condition cd1 = lock.newCondition();
    Condition cd2 = lock.newCondition();
    Condition cd3 = lock.newCondition();

    public  void print5(int total){
     
        lock.lock();
        try {
     
            //判断
            while (num!=1){
     
                cd1.await();//不会释放锁
            }
            //干活
            for (int i = 1; i <= 5 ; i++) {
     
                System.out.println(Thread.currentThread().getName()+
                        "\t "+total+"\t"+i);
            }
            //通知
            num = 2;
            cd2.signal();//唤醒线程2
        } catch (Exception e) {
     
            e.printStackTrace();
        } finally {
     
            lock.unlock();
        }
    }
    public  void print10(int total){
     
        lock.lock();
        try {
     
            //判断
            while (num!=2){
     
                cd2.await();//不会释放锁
            }
            //干活
            for (int i = 1; i <= 10 ; i++) {
     
                System.out.println(Thread.currentThread().getName()+
                        "\t "+total+"\t"+i);
            }
            //通知
            num = 3;
            cd3.signal();//唤醒线程3
        } catch (Exception e) {
     
            e.printStackTrace();
        } finally {
     
            lock.unlock();//主动释放锁
        }
    }
    public  void print15(int total){
     
        lock.lock();
        try {
     
            //判断
            while (num!=3){
     
                cd3.await();//不会释放锁
            }
            //干活
            for (int i = 1; i <= 15 ; i++) {
     
                System.out.println(Thread.currentThread().getName()+
                        "\t "+total+"\t"+i);
            }
            //通知
            num = 1;
            cd1.signal();//唤醒线程1

        } catch (Exception e) {
     
            e.printStackTrace();
        } finally {
     
            lock.unlock();
        }
    }
}
public class ThreadOrderAccess {
     

    public static void main(String[] args) {
     
        ShareData shareData = new ShareData();

        new Thread(()->{
     
            for (int i = 1; i <=10 ; i++) {
     
                shareData.print5(i);
                System.out.println("此轮结束");
            }
        },"AA").start();
        new Thread(()->{
     
            for (int i = 1; i <=10 ; i++) {
     
                shareData.print10(i);
                System.out.println("此轮结束");
            }
        },"BB").start();
        new Thread(()->{
     
            for (int i = 1; i <=10 ; i++) {
     
                shareData.print15(i);
                System.out.println("此轮结束");
            }
        },"CC").start();
    }
}

Lock与Syncronize的区别

1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;

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

3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;

4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;

5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)

6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

你可能感兴趣的:(JUC,juc)