学姐天天缠着问我JUC,搞得我没有时间打游戏,无奈之下我写下JUC基础,要她自己去研究 上

Posted Code_BinBin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学姐天天缠着问我JUC,搞得我没有时间打游戏,无奈之下我写下JUC基础,要她自己去研究 上相关的知识,希望对你有一定的参考价值。

引言

今天是星期一,翘了课在寝室玩农药,正当我要五杀的时候,学姐给我打了个电话,于是我的五杀没了。
在这里插入图片描述
“学弟,今天面试官问我了不了解JUC,没答出来怎么办?”学姐哭着问道
“面试官怎么说的啊?”我把自己痛失五杀的愤怒强行压制下去,毕竟这个是在我大一的时候对我照顾有加的学姐,无论是正常的校园生活和不正常的校园生活,要我舒舒服服的混到了大三,是、人要有一颗感恩的心,所以我还是忍住没有和她发脾气。
“面试官说日后再说”,学姐说道
“这样的吗?这个面试官可真不是什么好东西?”
“为什么这么说啊”?学姐不解的说道。
“没事学姐,我给你写一篇JUC的文章,你有时间看看就好了”
在这里插入图片描述

什么是 JUC

JUC就是 java.util 下的工具包、包、分类等。

在这里插入图片描述
“在我们学习JUC之前,先去回顾一下线程方面的知识,学姐你要是不会的话可以子去看一下别的博主的博客,我以后有时间会写”,我说道
“好的学弟”

普通的线程

  • Thread
  • Runnable 没有返回值、效率相比入 Callable 相对较低!
  • Callable 有返回值!

线程和进程

我之前就有写过一篇关于线程和进程的文章,可以先看看这篇文章

  • 进程:一个程序,QQ.exe Music.exe 程序的集合;
  • 一个进程往往可以包含多个线程,至少包含一个
  • Java默认有2个线程? mian、GC
  • 线程:开了一个进程 Typora,写字,自动保存(线程负责的)
  • 对于Java而言提供了:Thread、Runnable、Callable操作线程。

并发、并行

并发

当我们有若干个线程需要运行的时候,由于cpu处理速度很快,他会把若干个线程快速交替,就是多线程同时操作资源

并行

假如我们的电脑是36核的,36个cpu同时运行

可以用这个代码来检查一下自己电脑是几核的,我的是16核

public class Test1 { 
    public static void main(String[] args) { 
	  // 获取cpu的核数 
     // CPU 密集型,IO密集型 
  	  System.out.println(Runtime.getRuntime().availableProcessors());
     // 如果电脑是8核,则结果输出8
 	} 
}

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

线程有几个状态

答案:6个

public enum State {
    /**
     * Thread state for a thread which has not yet started.
     * 线程新生状态
     */
    NEW,
    /**
     * Thread state for a runnable thread.  A thread in the runnable
     * state is executing in the Java virtual machine but it may
     * be waiting for other resources from the operating system
     * such as processor.
     * 线程运行中
     */
    RUNNABLE,
    /**
     * Thread state for a thread blocked waiting for a monitor lock.
     * A thread in the blocked state is waiting for a monitor lock
     * to enter a synchronized block/method or
     * reenter a synchronized block/method after calling
     * {@link Object#wait() Object.wait}.
     * 线程阻塞状态
     */
    BLOCKED,
    /**
     * Thread state for a waiting thread.
     * A thread is in the waiting state due to calling one of the
     * following methods:
     * <ul>
     *   <li>{@link Object#wait() Object.wait} with no timeout</li>
     *   <li>{@link #join() Thread.join} with no timeout</li>
     *   <li>{@link LockSupport#park() LockSupport.park}</li>
     * </ul>
     *
     * <p>A thread in the waiting state is waiting for another thread to
     * perform a particular action.
     *
     * For example, a thread that has called <tt>Object.wait()</tt>
     * on an object is waiting for another thread to call
     * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
     * that object. A thread that has called <tt>Thread.join()</tt>
     * is waiting for a specified thread to terminate.
     * 线程等待状态,死等
     */
    WAITING,
    /**
     * Thread state for a waiting thread with a specified waiting time.
     * A thread is in the timed waiting state due to calling one of
     * the following methods with a specified positive waiting time:
     * <ul>
     *   <li>{@link #sleep Thread.sleep}</li>
     *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
     *   <li>{@link #join(long) Thread.join} with timeout</li>
     *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
     *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
     * </ul>
     * 线程超时等待状态,超过一定时间就不再等
     */
    TIMED_WAITING,
    /**
     * Thread state for a terminated thread.
     * The thread has completed execution.
     * 线程终止状态,代表线程执行完毕
     */
    TERMINATED;
}

wait/sleep 区别

第一:两者来自不同的父类

  • wait => Object
  • sleep => Thread

第二:两者释放锁不一样

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

第三:两者使用的范围是不同的

  • wait 必须在同步代码块中使用
  • sleep 可以再任何地方睡眠

Synchronized锁

传统 Synchronized锁:一个简单的卖票例子

package com.znb;

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

public class Test01 {
   public static void main(String[] args) {
        //并发:多个线程同时操作一个资源类,把资源类丢入线程
        Ticket ticket = new Ticket();

        // @FunctionalInterface 函数式接口,jdk1.8 lambada表达式
        new Thread(() -> {
            for (int i = 1; i < 50; i++) {
                ticket.sale();
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 1; i < 50; i++) {
                ticket.sale();
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 1; i < 50; i++) {
                ticket.sale();
            }
        }, "C").start();
    }
}

//资源类 OOP
class Ticket {
    //属性、方法
    private int number = 50;

    // 卖票的方式
    // synchronized 本质: 队列,锁
    public synchronized void sale() {
        if (number > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出了" +
                    (50-(--number)) + "张票,剩余:" + number + "张票");
        }
    }

}

Lock锁

公平锁(FairLock)

十分公平,分先来后到,不准插队

非公平锁 (UnFairLock)

不公平,可以插队

一般都是默认非公平锁,因为有时候如果一个线程的延时是10分钟,另一个线程没有延时,如果延时十分钟的线程先到,那么后一个线程就要等十分钟。

将上面的卖票例子用lock锁 替换synchronized:

package com.znb;

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

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

class Ticket{
    private  int number =100;
    Lock lock=new ReentrantLock();
    public synchronized void sale(){
        if (number>0){
            System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"张票子");
        }
    }
}

Synchronized 和 Lock 区别:

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

生产者和消费者问题

非JUC版

可以参考一下我之前的博客

package com.znb.pc;

public class Test01 {
    public static void main(String[] args) {
        A a=new A();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    a.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    a.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    a.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    a.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
    }
}
class A{
    private int sum=0;
    public synchronized void incr() throws InterruptedException {
        while(sum!=0){
            this.wait();
        }
        sum++;
        System.out.println(Thread.currentThread().getName()+"==》"+sum);
        this.notifyAll();
    }
    public synchronized void decr() throws InterruptedException {
        while (sum==0){
            this.wait();
        }
        sum--;
        System.out.println(Thread.currentThread().getName()+"==》"+sum);
        this.notifyAll();
    }
}

这里我们通过线程A唤醒B,B唤醒C以此类推,并且这里我们用的是while,因为如果我们用的是if,并且线程大于2个,那么就会存在虚假唤醒,出现错误
在这里插入图片描述

使用while的结果

在这里插入图片描述

使用if的结果

在这里插入图片描述
我们可以看见,出现了-169,-170这样错误的数据,所以这里记得用while

JUC版

这里引进一个新东西,叫Condition

在这里插入图片描述

代码实现

package com.znb.pc;

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

public class Test02 {
    public static void main(String[] args) {
        B a=new B();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    a.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    a.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    a.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    a.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
    }
}
class B{
    private int sum=0;
    Lock lock=new ReentrantLock();
    Condition condition=lock.newCondition();
    public  void incr() throws InterruptedException {
        lock.lock();
        try {
            while(sum!=0){
                condition.await();
            }
            sum++;
            System.out.println(Thread.currentThread().getName()+"==》"+sum);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
    public  void decr() throws InterruptedException {
        lock.lock();
        try {
            while (sum==0){
                condition.await();
            }
            sum--;
            System.out.println(Thread.currentThread().getName()+"==》"+sum);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}

当我们使用Condition 的时候,我们唤醒线程和要线程等待就不是用什么 waitsleepnotifyAll这些东西了,我们需要使用 await 等待,signalAll唤醒

在这里插入图片描述

但是细心的我们发现,我们线程的顺序是A->B->C->D,但是最后输出的答案并不是这样,那要怎么办呢?没关系JDK源码的作者也想到了这个问题。

package com.znb.pc;

import java.util.concurrent.locks.Condition以上是关于学姐天天缠着问我JUC,搞得我没有时间打游戏,无奈之下我写下JUC基础,要她自己去研究 上的主要内容,如果未能解决你的问题,请参考以下文章

这个数据太骚!搞得我都激动了。

这个数据太骚!搞得我都激动了。

pygame游戏用Python实现一个蔡徐坤大战篮球的小游戏,可还行?附源码

OAuth,JWT ,OIDC你们搞得我好乱啊

孩子贪玩游戏,不如玩少儿编程开发大脑

360软件小助手一键加速的设置