JUC-1

发布时间 2023-09-23 10:19:41作者: 新至所向

JUC-1

1、什么是JUC

源码+官方文档面试高频问!

java.util工具包、包、分类
业务∶普通的线程代码Thread
Runnable没有返回值、效率相比入Callable 相对较低!

2、线程和进程

  • 线程、进程,如果不能使用一句话说出来的技术,不扎实!
  • 进程:—个程序,QQ.exe Music.exe程序的集合;
  • 一个进程往往可以包含多个线程,至少包含一个!
  • Java默认有几个线程?2个mian、GC
  • 线程:开了一个进程Typora,写字,自动保存(线程负责的)
  • 对于Java而言:Thread、Runnable、Callable
  • Java真的可以开启线程吗?开不了

并发、并行

  • 并发编程:并发、并行
  • 并发(多线程操作同一个资源)
    • CPU一核,模拟出来多条线程,天下武功,唯快不破,快速交替
  • 并行(多个人一起行走)
    • CPU 多核,多个线程可以同时执行;
//获取cpu的核数
        //CPU密集型,IO蜜集型
        System.out.println(Runtime.getRuntime().availableProcessors());

并发编程的本质:充分利用CPU的资源

线程有几个状态

6

public enum state {
//新生
NEW,
//运行
    RUNNABLE,
//阻塞
    BLOCKED,
//等待,死死地等
    WAITING,
//超时等待
TIMED_WAITING,
//终止
TERMINATED;
}

wait/sleep 区别

  1. 来自不同的类

    • wait => Object
    • sleep => Thread
  2. 关于锁的释放
    wait 会释放锁,sleep睡觉了,抱着锁睡觉,不会释放!

  3. 使用的范围是不同的

    • wait必典在同步代码块中
    • sleep可以再任何地方睡
  4. 是否需要捕获异常

    • wait不需要捕获异常
    • sleep 必须要捕获异常
package demo01;

public class Day92200 {
    public static void main(String[] args) {
        //获取cpu的核数
        //CPU密集型,IO蜜集型
      //  System.out.println(Runtime.getRuntime().availableProcessors());

        //并发:多线程操作同一个资源类,把资源类丢入线程
        Ticket ticket = new Ticket();

        new Thread(()-> {
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        },"aa").start();
       new Thread(()-> {
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        },"bb").start();
       new Thread(()-> {
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        },"cc").start();


    }
}
//资源类  OOP
class Ticket{
    //属性。方法
    private int number=50;
    //卖票的方式
    public void sale(){
        if (number>0){
            System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余:"+number);
        }
    }
}

3、Lock锁(重点)

真正的多线程开发,公司中的开发

线程就是一个单独的资源类,没有任何附属的操作!

1、属性、方法

  • 公平锁:十分公平:可以先来后到
  • 非公平锁:十分不公平:可以插队(默认)
package demo01;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Day92201 {
    public static void main(String[] args) {

        //并发:多线程操作同一个资源类,把资源类丢入线程
        Ticket1 ticket = new Ticket1();

        new Thread(()->{for (int i = 0; i < 50; i++) ticket.sale();},"aa").start();
        new Thread(()->{for (int i = 0; i < 50; i++) ticket.sale();},"bb").start();
        new Thread(()->{for (int i = 0; i < 50; i++) ticket.sale();},"cc").start();



    }
}
//Lock三部曲
//1、new ReentrantLock( );
// 2、 Lock.Lock(); //加锁
//3、finaLLy=>Lock. unLock(); //解锁
class Ticket1{
    //属性。方法
    private int number=50;
    Lock lock=new ReentrantLock();

    //卖票的方式
    public void sale(){
        lock.lock();//加锁
        try {
            if (number>0){
                System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余:"+number);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
}

Synchronized 和Lock区别

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

4、生产者和消费者问题

生产者和消费者问题 Synchronized版

package demo01;
/*
线程之间的通信问题:生产者和消费者问题!等待唤醒,通知唤醒
线程交替执行 A B 操作同一个变量num =0
A num+1
B num-1

 */
public class AA {
    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) {
                    throw new RuntimeException(e);
                }
            }
        },"aa").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"bb").start();

    }
}

//等待,业务,通知
class Data{//资源类
    private int number=0;

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

问题存在,A B CD 4个线程!虚假唤醒

if 改为while判断

image-20230922151757260

package demo01;
/*
线程之间的通信问题:生产者和消费者问题!等待唤醒,通知唤醒
线程交替执行 A B 操作同一个变量num =0
A num+1
B num-1

 */
public class AA {
    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) {
                    throw new RuntimeException(e);
                }
            }
        },"aa").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"bb").start();
            new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"cc").start();
            new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"dd").start();

    }
}

//等待,业务,通知
class Data{//资源类
    private int number=0;

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

JUC版的生产者和消费者问题

image-20230922152517100

通过Lock找到Condition

package demo01;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BB {
    public static void main(String[] args) {
        Data1 data1 = new Data1();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                    data1.increment();
            }
        },"aa").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                    data1.decrement();
            }
        },"bb").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                    data1.increment();
            }
        },"cc").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                    data1.decrement();
            }
        },"dd").start();

    }
}

//等待,业务,通知
class Data1{//资源类
    private int number=0;
    Lock lock=new ReentrantLock();
    Condition condition=lock.newCondition();
    // condition . await(); //等待
    // condition .signalALL(); //唤醒全部

    //+1
    public  void increment() {
        lock.lock();
        try {
            //业务代码
            while (number!=0){
                //等待
                condition.await();
            }
                number++;
                System.out.println(Thread.currentThread().getName()+"--->"+number);
                //通知其他线程,我+1完毕了
                condition.signalAll();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }

    }
    //-1
    public  void decrement()  {
        lock.lock();
        try {
            while (number==0){
                //等待
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName()+"--->"+number);
            //通知其他线程,我-1完毕了
            condition.signalAll();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }

    }
}

a-b-c

package demo01;

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 CC {
    public static void main(String[] args) {
        Data3 data3 = new Data3();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data3.printA();
            }
        }, "a").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data3.printB();
            }
        }, "b").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data3.printC();
            }
        }, "c").start();

    }
}

class Data3 {//资源类 lock
    private Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();
    private int number = 1;//1a  2b  3c

    public void printA() {
        lock.lock();
        try {
            //业务,判断->执行->通知
            while (number != 1) {
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "-->aaa  " + number);
            number = 2;
            condition2.signal();//唤醒,唤醒指定的人,B


        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public void printB() {
        lock.lock();
        try {
            //业务,判断->执行->通知
            while (number != 2) {
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName() + "-->bbb  " + number);
            number = 3;
            condition3.signal();//唤醒,唤醒指定的人,c
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public void printC() {
        lock.lock();
        try {
            //业务,判断->执行->通知
            while (number != 3) {
                condition3.await();
            }//最后一步不能是等待,只能是唤醒
            System.out.println(Thread.currentThread().getName() + "-->aaa  " + number);
            number = 1;
            condition1.signal();//唤醒,唤醒指定的人,A

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

}

5、8锁现象

如何判断锁的是谁!永远的知道什么锁,锁到底锁的是谁!

对象、Class

synchronized锁的对象是方法的调用者!两个方法用的是同一个锁,谁先拿到谁执行!(上厕所,一个对象一个坑,谁先进去谁先用。但是可以new多个对象)

static静态方法
类一加载就有! class 模板,锁的是cLass(上厕所,只有一个类.class的坑,)

1个静态的同步方法,1个普通的同步方法,一个对象,先打印发短信?打电话?

  • 打电话(这两个方法是两把锁,一个是对象锁,一个是class锁)

1个静态的同步方法,1个普通的同步方法,2个对象,先打印发短信?打电话?

  • 打电话(这两个方法是一共3把锁,普通的同步使用的一个是对象锁,static的同步使用的一个是class锁)

小结

new this具体的一个手机

static Class 唯一的一个模板