JUC(狂神)

JUC

1、什么是JUC

JUC就是java.util.concurrent下面的类包,专门用于多线程的开发。

2、进程和线程

线程、进程,(如果不能用一句话说出来的技术,不扎实)

进程:一个程序,QQ.exe,Music.exe 程序的集合
一个进程往往可以包含多个线程,至少包含一个!
java默认有几个线程?2个 main 、GC
线程:开了个进程Typora ,写字,自动保存(线程负责的)

对于Java而言:Thread Runnable Callable

Java真的可以开启线程吗? 开不了的

Java是没有权限去开启线程、操作硬件的,这是一个native的本地方法,它调用的底层的C++代码

 public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
	//这是一个C++底层,Java是没有权限操作底层硬件的
    private native void start0();

并发、并行

并发编程:并发、并行

并发:多线程操作同一个资源

  • CPU一核,模拟出来多条线程 ,天下武功,唯快不破。那么我们就可以使用CPU快速交替,

并行:多个人一起行走

  • CPU多核,多个线程可以同时执行:线程池
public class Test {
    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().availableProcessors());
    }

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

线程有几种状态

public enum State {

    	//新生
        NEW,

    	//运行
        RUNNABLE,

    	//阻塞
        BLOCKED,

    	//等待
        WAITING,

    	//超时等待
        TIMED_WAITING,

    	//终止
        TERMINATED;
    }

wait/sleep区别

1.来着不同的类

wait => Object

sleep => Thread

一般情况下企业中使用的休眠是:

TimeUnit.DAYS.sleep(1); //休眠1天
TimeUnit.SECONDS.sleep(1); //休眠1s

2.关于锁的释放

wait会释放锁,

sleep睡觉了,抱着锁睡觉,不会释放!

3.使用的范围是不同的

wait 必须在同步代码块中;

sleep 可以在任何地方睡

4.是否需要捕获异常

wait不需要捕获异常

sleep 必须要捕获异常

3、Lock锁(重点)

Synchronized

package com.zht;

public class Demo01 {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(()->{
            for (int i=0;i<40;i++){
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i=0;i<40;i++){
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i=0;i<40;i++){
                ticket.sale();
            }
        },"C").start();
    }
}
// 资源类 OOP 属性、方法
class Ticket{
    private int number = 30;
    //卖票的方式
    public synchronized void sale(){
        if (number>0){
            System.out.println(Thread.currentThread().getName() + "卖出了第" + (number--) + "张票剩余" + number + "张票");
        }
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2IpiEfD4-1632641185491)(C:\Users\User\AppData\Roaming\Typora\typora-user-images\1632577518422.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RVUMLzOQ-1632641185493)(C:\Users\User\AppData\Roaming\Typora\typora-user-images\1632577023332.png)]

image-20200810221731649

公平锁:十分公平,可以先来后到

非公平锁:十分不公平,可以插队(默认)

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

public class Demo02 {
    public static void main(String[] args) {
        Ticket1 ticket = new Ticket1();
        new Thread(()->{ for (int i=0;i<40;i++) ticket.sale(); },"A").start();
        new Thread(()->{ for (int i=0;i<40;i++) ticket.sale(); },"B").start();
        new Thread(()->{ for (int i=0;i<40;i++) ticket.sale(); },"C").start();

    }
}

// lock 三部曲
//1.new ReentrantLock
//2.Lock.lock() 加锁
//3.lock.unlock()解锁
class Ticket1{
    private int number = 30;
    //卖票的方式

    Lock lock = new ReentrantLock();

    public void sale(){
        lock.lock(); //加锁
        try {
            if (number>0){
                System.out.println(Thread.currentThread().getName() + "卖出了第" + (number--) + "张票剩余" + number + "张票");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

Synchronized和Lock锁的区别

1.Synchronized 是默认的关键字;Lock是一个类

2.Synchronized 无法判断获取锁的状态;Lock可以判断是否获得了锁

3.Synchronized 会自动释放锁;lock必须手动释放锁!如果不释放锁,死锁

4.Synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去

5.Synchronized 可重入锁,不可中断的,非公平的;Lock

6.Synchronized 适合锁少量的同步代码块,Lock适合锁大量的同步代码

锁是什么,任何判断锁的是谁

4、生产者和消费者问题

面试的:单例模式,排序算法,生产者和消费者,死锁

生产者和消费者问题 Synchronized A

package com.zht.pc;

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

问题存在(虚假唤醒)

问题,如果有四个线程,会出现虚假唤醒

image-20200810224629273

image-20200810224826214

解决方式 ,if 改为while即可,防止虚假唤醒

结论:就是用if判断的话,唤醒后线程会从wait之后的代码开始运行,但是不会重新判断if条件,直接继续运行if代码块之后的代码,而如果使用while的话,也会从wait之后的代码运行,但是唤醒后会重新判断循环条件,如果不成立再执行while代码块之后的代码块,成立的话继续wait。

这也就是为什么用while而不用if的原因了,因为线程被唤醒后,执行开始的地方是wait之后

package com.zht.pc;

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();new Thread(()->{
            for (int i=0;i<10;i++){
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();new Thread(()->{
            for (int i=0;i<10;i++){
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}


//等到 ,通知
class Data{
    private int number = 0;

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

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

image-20200811094721678

package com.zht.pc;

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

public class B {

    public static void main(String[] args) {
        Data1 data = new Data1();
        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();new Thread(()->{
            for (int i=0;i<10;i++){
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();new Thread(()->{
            for (int i=0;i<10;i++){
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}


//等到 ,通知
class Data1{
    private int number = 0;

     Lock lock= new ReentrantLock();
    Condition condition = lock.newCondition();
    //等待    condition.await();
    //喚醒全部    condition.signalAll();
    //-1
    public  void increment() throws InterruptedException {
        lock.lock();

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

Condition 精准的通知和唤醒线程

package com.zht.pc;

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

public class C {

    public static void main(String[] args) {
        Data2 data2 = new Data2();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data2.printA();
            }
        }).start();new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data2.printB();
            }
        }).start();new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data2.printC();
            }
        }).start();
    }
}


//等到 ,通知
class Data2{

     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");
            //唤醒:唤醒指定的人:2
            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;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    //生产线:下单->支付->交易->物流
}

5、8锁现象

如何判断锁的是谁!锁到底锁的是谁?

对象、class

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值