JUC并发编程 Day01 (JUC、Lock、生产者和消费者问题、JUC生消问题、Condition)

什么是JUC

Java Util Concurrent

业务:普通的线程代码不能满足
Runable 没有返回值,效率相比于Callable相对较低!
java是没权限开启线程的,调用的是底层的C++

线程的三种方式
Thread Runable Callable

并发、并行

  • 并发(多个线程操作一个资源)
    – CPU一核、快速交替
  • 并行(多个人一起行走)
    – CPU多核,多个进程一起执行(提高效率使用线程池即可)

并发编程的本质:充分利用CPU的资源
所有的公司都很看重的东西

线程有几个状态

新生、运行、阻塞、等待(死等)、超时等待(超期不等待)、终止
NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED

wati/sleep 区别

1、来自不同的类
wait => Object
sleep => Thread (sleep是线程特有的)

2、关于锁的释放
wait 会释放锁
sleep 不会释放锁(抱着锁睡)

3、使用范围不同
wait 必须在同步代码块中使用
sleep 可以在任何地方睡


3、Lock锁(重点)

lock

JUC并发编程 Day01 (JUC、Lock、生产者和消费者问题、JUC生消问题、Condition)_第1张图片

JUC并发编程 Day01 (JUC、Lock、生产者和消费者问题、JUC生消问题、Condition)_第2张图片

  • 公平锁:不可插队
  • 非公平锁:可以插队,JAVA默认使用这个

用lamda表达式代替Thread new Runnable写法

public class Ticket {
     
    public static void main(String[] args) {
     
        SaleTic saleTic = new SaleTic();
        new Thread(new Runnable() {
     
            @Override
            public void run() {
     
                saleTic.sale();
            }
        }).start();
        new Thread(()->{
     
            for (int i = 0; i < 40; i++) {
     
                saleTic.sale();
            }
            },"A").start();
        new Thread(()->{
     
            for (int i = 0; i < 40; i++) {
     
                saleTic.sale();
            }
            },"B").start();
    }
}

// 传统锁
class  SaleTic{
     
    private int number = 50;
	
    public synchronized void sale(){
     
        if(number > 0 ){
     
            System.out.println((Thread.currentThread().getName()+"卖出了"+(number--)+"张票,剩余:"+number));
        }
    }
}

//  lock三部曲
//  1、new锁 new ReentrantLock()
//  2、加锁 lock.lock()
//  3、解锁 lock.unlock()
class  SaleTic{
     
    private int number = 50;

    Lock lock = new ReentrantLock();

    public void sale(){
     
        try {
     
            lock.lock();// 加锁

            // 业务代码
            if(number > 0 ){
     
                System.out.println((Thread.currentThread().getName()+"卖出了"+(number--)+"张票,剩余:"+number));
            }

        } catch (Exception e) {
     
            e.printStackTrace();
        }finally {
     
            lock.unlock(); // 解锁
        }

    }

}

synchronized 和 Lock 的区别

  • synchronized 是Java关键字, Lock是一个Java类
  • synchronized 是无法判断获锁的状态,Lock可以判断是否获取了锁
  • synchronized 是自动释放锁,Lock必须是手动释放锁!如果不释放锁,死锁
  • synchronized 线程1(获得锁)、线程2(等待);Lock锁就不一定会等待下去;
  • synchronized 是可重入锁,不可以中断的,非公平:Lock,可重入锁,可以判断锁,非公平(可以自己设置)
  • synchronized 适合锁少量的代码同步问题,Lock锁适合锁大量的同步代码

锁是什么,如何判断锁的是谁?

4、生产者和消费者问题

生产者和消费者问题 synchronized

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 number = 0;

    //+1
    public synchronized void increment() throws InterruptedException {
     
        if(number != 0){
     
            //等待
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        // 通知线程+1完毕
        this.notifyAll();
    }
    //-1
    public synchronized  void decrement() throws InterruptedException {
     
        if(number == 0){
     
            //等待
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        // 通知线程-1完毕
        this.notifyAll();
    }
}

问题存在 :A B C D 4个线程!还安全么

不安全,会出现虚假唤醒情况,if会跳过判断执行wait之后的代码,while不会
处理的方法: 把if()换成while()即可解决问题

		while(number == 0){
     
            //等待
            this.wait();
        }

原因: 因为wait的时候是在if里面wait了,当被再次唤醒时,代码不会再次判断if,而是从if里面的wait继续向下执行,所以会出错
JUC并发编程 Day01 (JUC、Lock、生产者和消费者问题、JUC生消问题、Condition)_第3张图片

JUC版的生产者与消费者

JUC中的wait()和notify()代替者
JUC并发编程 Day01 (JUC、Lock、生产者和消费者问题、JUC生消问题、Condition)_第4张图片

Condition 对比 Synchronized 的优势/升级点

Condition可以进行精准控制唤醒,将一个lock可以加多个condition

class Data3{
     

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private Integer number = 1;

    public void printA(){
     
        lock.lock();
        try {
     
            //业务
            while(number != 1){
     
                condition.await();
            }
            System.out.println(Thread.currentThread().getName()+":AAAAAAAAAAAAA");
            number = 2;
            condition2.signal();
        } catch (Exception e) {
     
            e.printStackTrace();
        }finally {
     
            lock.unlock();
        }
    }

    public void printB(){
     
        lock.lock();
        try {
     
            //业务
            while(number != 2){
     
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+":BBB");
            number = 3;
            condition3.signal();
        } catch (Exception e) {
     
            e.printStackTrace();
        }finally {
     
            lock.unlock();
        }
    }

    public void printC(){
     
        lock.lock();
        try {
     
            //业务
            while(number != 3){
     
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+":CCC");
            number = 1;
            condition.signal();
        } catch (Exception e) {
     
            e.printStackTrace();
        }finally {
     
            lock.unlock();
        }
    }
}

你可能感兴趣的:(面试经验总结,知识回顾,多线程,java)