搜索内容

有一个问题?

如果您有任何疑问,可以在下面询问或输入您要寻找的!

狂神JUC笔记(上)

生成海报
兴趣使然的草帽路飞
阅读需:0

狂神说JUCbilbil视频链接详细地址:https://www.bilibili.com/video/BV1B7411L7tE


1、什么叫 JUC

JUC便是 java.util 下的工具箱、包、归类等。

在这里插入图片描述

一般的进程编码:

  • Thread

  • Runnable 沒有传参、高效率对比入 Callable 相对性较低!

  • Callable 有传参!

2、线程和进程

进程、过程,假如不可以应用一句话说出来的技术性,不扎扎实实!

  • 过程:一个程序流程,QQ.exe Music.exe 程序流程的结合;

  • 一个过程通常能够包括好几个进程,最少包括一个!

  • Java默认设置有两个进程? mian、GC

  • 进程:开过一个过程 Typora,写毛笔字,全自动储存(进程承担的)

  • 针对Java来讲出示了:Thread、Runnable、Callable实际操作进程。

Java 确实能够打开进程吗? 回答是:开不上的!

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 ,好几个进程能够另外实行; eg: 线程池!
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:
     * 
    *
  • {@link Object#wait() Object.wait} with no timeout
  • *
  • {@link #join() Thread.join} with no timeout
  • *
  • {@link LockSupport#park() LockSupport.park}
  • *
* *

A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called Object.wait() * on an object is waiting for another thread to call * Object.notify() or Object.notifyAll() on * that object. A thread that has called Thread.join() * 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: *

    *
  • {@link #sleep Thread.sleep}
  • *
  • {@link Object#wait(long) Object.wait} with timeout
  • *
  • {@link #join(long) Thread.join} with timeout
  • *
  • {@link LockSupport#parkNanos LockSupport.parkNanos}
  • *
  • {@link LockSupport#parkUntil LockSupport.parkUntil}
  • *
* 进程请求超时等候情况,超出一定時间就不会再等 */ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. * 进程停止情况,意味着进程实行结束 */ TERMINATED; }

wait/sleep 差别

1、二者来源于不一样的类

  • wait => Object
  • sleep => Thread

2、有关锁的释放出来

  • wait 会释放出来锁
  • sleep 睡着了,怀着锁入睡,不容易释放出来!

3、应用的范畴是不一样的

  • wait 务必在同歩代码块中应用
  • sleep 能够再任何地方睡眠质量

3、Synchronized锁

传统式 Synchronized锁

看来一个线程同步售票事例

package com.haust.juc01;

/*
 * @Auther: csp1999
 * @Date: 2020/07/21/13:59
 * @Description: 售票事例
 */
public class SaleTicketTDemo01 {

    /*
     * 真实的线程同步开发设计,企业中的开发设计,减少耦合度
     * 进程便是一个独立的資源类,沒有一切附设的实际操作!
     * 1、 特性、方式
     */
    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 + "张票");
        }
    }
}

4、Lock锁(关键)

Lock 插口

在这里插入图片描述

在这里插入图片描述

  • 公平公正锁:十分公平公正,进程实行次序依照先来后到次序

  • 非公平公正锁:十分不合理:能够排队 (默认设置锁)

将上边的售票事例用lock锁 更换synchronized:

package com.haust.juc01;

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

/*
 * @Auther: csp1999
 * @Date: 2020/07/21/13:59
 * @Description: 售票事例2
 */
public class SaleTicketTDemo02 {

    public static void main(String[] args) {
        //高并发:好几个进程另外实际操作一个資源类,把資源类丢进进程
        Ticket2 ticket = new Ticket2();

        // @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();
    }
}

//Lock 3流程
// 1. new ReentrantLock();
// 2. lock.lock()  上锁
// 3. lock.unlock() 开启
class Ticket2 {
    //特性、方式
    private int number = 50;

    Lock lock = new ReentrantLock();

    // 售票方法
    public void sale() {

        lock.lock();// 上锁

        try {
            // 业务流程编码
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "售出了" +
                        (50 - (--number)) + "张票,剩下:" + number + "张票");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();// 开启
        }
    }
}

Synchronized 和 Lock 差别:

  • 1、Synchronized 内嵌的Java关键词, Lock 是一个Java类

  • 2、Synchronized 没法分辨获得锁的情况,Lock 能够分辨是不是获得到锁

  • 3、Synchronized 会全自动释放出来锁,lock 务必要手动式释放出来锁!如果不释放出来锁,死锁

  • 4、Synchronized 进程 1(得到锁,假如进程1堵塞)、进程2(等候,傻乎乎等);Lock锁也不一定会等候下来;

  • 5、Synchronized 可重入锁,不能终断的,非公平公正;Lock ,可重入锁,能够分辨锁,非公平公正(能够自身设定);

  • 6、Synchronized 合适锁小量的编码同歩难题,Lock 合适锁很多的同歩编码!

锁是啥,怎么知道锁的是啥!

这个问题在以后会举例说明剖析。

5、经营者和顾客难题

招聘面试常见的难题:单例模式、快速排序算法、经营者和顾客、死锁

经营者和顾客难题 Synchronized 版

package com.haust.pc;

/**
 * 进程中间的通讯难题:经营者和顾客难题!  等候唤起,通告唤起
 * 进程更替实行  A   B 实际操作同一个自变量   num = 0
 * A num+1
 * B num-1
 */
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.increment();
                } 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 {
        /*
        假定 number这时相当于1,即早已被生产制造了商品
        假如这儿用的是if分辨,假如这时A,C2个经营者进程角逐increment()方式执行权
        假定A取得执行权,历经分辨number!=0创立,则A.wait()逐渐等候(wait()会释放出来锁),随后C尝试去实行
        生产制造方式,但仍然分辨number!=0创立,则B.wait()逐渐等候(wait()会释放出来锁)
        恰巧此刻顾客进程进程B/D去消費了一个商品,使number=0随后,B/D消費完后启用this.notifyAll();
        此刻两个准备中的经营者进程再次生产制造商品,而这时number++ 实行了2次
        同样,反复所述全过程,经营者进程再次wait()等候,顾客启用this.notifyAll();
        随后经营者再次超前的生产制造,最后造成 ‘生产过剩’,即number大于1
        if(number != 0){
            // 等候
            this.wait();
        }*/
        while (number != 0) { // 留意这儿不能用if 不然会发生虚报唤起难题,解决方案将if换为while
            // 等候
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        // 通告别的进程,我+1结束了
        this.notifyAll();
    }

    //-1
    public synchronized void decrement() throws InterruptedException {
        while (number == 0) {
            // 等候
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        // 通告别的进程,我-1结束了
        this.notifyAll();
    }
}

难题存有,A B C D 4 个进程! 虚报唤起

最先到CHM 官方网文本文档 java.lang包下 寻找Object ,随后寻找wait()方式:

在这里插入图片描述

因而所述编码中务必应用while分辨,而不可以应用if

JUC版的经营者和顾客难题

请添加图片描述

官方网文本文档中根据Lock 寻找 Condition

请添加图片描述

点进Condition 查询

请插入图片叙述

请添加图片描述

编码完成:

package com.haust.pc;

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

/**
 * 进程中间的通讯难题:经营者和顾客难题!  等候唤起,通告唤起
 * 进程更替实行  A   B 实际操作同一个自变量   num = 0
 * A num+1
 * B num-1
 */
public class B {
    public static void main(String[] args) {
        Data2 data = new Data2();

        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.increment();
                } 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 Data2 { // 数据 資源类

    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.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    //-1
    public  void decrement() throws InterruptedException {
        lock.lock();
        try {
            while (number == 0) {
                // 等候
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            // 通告别的进程,我-1结束了
            condition.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
}

一切一个新的技术性,肯定并不是只不过是遮盖了原先的技术性,是有其对旧技术性的优点和填补!

Condition 精确的通告和唤起进程

所述程序执行結果如图所示:

请插入图片叙述

难题:ABCD进程 占领实行的次序是任意的,假如想让ABCD进程井然有序实行,该怎样改善编码?

编码完成:

package com.haust.pc;

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 C {

    public static void main(String[] args) {
        Data3 data = new Data3();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printA();
            }
        }, "A").start();

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

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

}

class Data3 { // 資源类 Lock

    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int number = 1; 
    // number=1 A实行  number=2 B实行 number=3 C实行

    public void printA() {
        lock.lock();
        try {
            // 业务流程,分辨-> 实行-> 通告
            while (number != 1) {
                // A等候
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>AAAAAAA");
            // 唤起,唤起特定的人,B
            number = 2;
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printB() {
        lock.lock();
        try {
            // 业务流程,分辨-> 实行-> 通告
            while (number != 2) {
                // B等候
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>BBBBBBBBB");
            // 唤起,唤起特定的人,c
            number = 3;
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC() {
        lock.lock();
        try {
            // 业务流程,分辨-> 实行-> 通告
            // 业务流程,分辨-> 实行-> 通告
            while (number != 3) {
                // C等候
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>CCCCC ");
            // 唤起,唤起特定的人,A
            number = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

检测結果:

请添加图片描述

6、8锁状况

前边明确提出一个难题:怎么知道锁的到底是谁!了解什么叫锁,锁究竟锁的到底是谁!

深刻领会大家的锁

synchronized 锁的目标是方式的调用者

编码举例说明1:

package com.haust.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁,便是有关锁的八个难题
 * 1、规范状况下,2个进程先复印 发信息還是 先复印 通电话? 1/发信息  2/通电话
 * 1、sendSms延迟时间4秒,2个进程先复印 发信息還是 通电话? 1/发信息  2/通电话
 */.
public class Test1 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        // 锁的存有
        new Thread(()->{
            phone.sendSms();
        },"A").start();

        // 捕捉
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            phone.call();
        },"B").start();
    }
}

class Phone{

    // synchronized 锁的目标是方式的调用者!、
    // 2个方式用的是同一个目标启用(同一个锁),谁先取得锁谁实行!
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);// 怀着锁睡眠质量
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发信息");
    }

    public synchronized void call(){
        System.out.println("通电话");
    }

}

// 先实行 发信息,后实行通电话

一般方式沒有锁!并不是同歩方式,也不受锁的危害,一切正常实行

编码举例说明2:

package com.haust.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 3、 提升了一个一般方式后!先实行发信息還是Hello?// 一般方式
 * 4、 2个目标,2个同歩方式, 发信息還是 通电话? // 通电话
 */
public class Test2  {
    public static void main(String[] args) {
        // 2个目标,2个调用者,俩把锁!
        Phone2 phone1 = new Phone2();
        Phone2 phone2 = new Phone2();

        //锁的存有
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        // 捕捉
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            phone2.call();
        },"B").start();
        new Thread(()->{
            phone2.hello();
        },"C").start();
    }
}

class Phone2{

    // synchronized 锁的目标是方式的调用者!
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发信息");
    }

    public synchronized void call(){
        System.out.println("通电话");
    }

    // 这儿沒有锁!并不是同歩方式,不会受到锁的危害
    public void hello(){
        System.out.println("hello");
    }
}

// 先实行通电话,然后实行hello,最终实行发信息

**不一样案例目标的Class类模板只有一个,static静态数据的同歩方式,锁的是Class **

编码举例说明3:

package com.haust.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 5、提升2个静态数据的同歩方式,只有一个目标,先复印 发信息?通电话?
 * 6、2个目标!提升2个静态数据的同歩方式, 先复印 发信息?通电话?
 */
public class Test3  {
    public static void main(String[] args) {
        // 2个目标的Class类模板只有一个,static,锁的是Class
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();

        //锁的存有
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        // 捕捉
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}

// Phone3唯一的一个 Class 目标
class Phone3{

    // synchronized 锁的目标是方式的调用者!
    // static 静态方法
    // 类一载入就拥有!锁的是Class
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();   }
        System.out.println("发信息");
    } 

    public static synchronized void call(){
        System.out.println("通电话");
    }
}

// 先实行发信息,后实行通电话

编码举例说明4:

package com.haust.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 7、一个静态数据的同歩方式,一个一般的同歩方式 ,一个目标,先复印 发信息?通电话?
 * 8、一个静态数据的同歩方式,一个一般的同歩方式 ,2个目标,先复印 发信息?通电话?
 */
public class Test4  {
    public static void main(String[] args) {
        // 2个目标的Class类模板只有一个,static,锁的是Class
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        //锁的存有
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        // 捕捉
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}

// Phone3唯一的一个 Class 目标
class Phone4{

    // 静态数据的同歩方式 锁的是 Class 类模板
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发信息");
    }

    // 一般的同歩方式  锁的调用者(目标),二者锁的目标不一样,因此 不用等候
    public synchronized void call(){
        System.out.println("通电话");
    }
}

// 7/8 二种状况下,全是先实行通电话,后实行发信息,由于二者锁的目标不一样,
// 静态数据同歩方式锁的是Class类模板,一般同歩方式锁的是实例化的目标,
// 因此 无需等候前面一种开启后 后面一种才可以实行,只是二者并行执行,由于发信息休眠状态4s
// 因此 通电话先实行。

总结

  • new this 实际的一个手机
  • static Class 唯一的一个模版

7、结合类不安全

List 不安全

**List、ArrayList 等在高并发线程同步标准下,不可以完成信息共享,好几个进程另外启用一个list目标情况下便会发生高并发改动出现异常ConcurrentModificationException **。

编码举例说明:

package com.haust.unsafe;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

// java.util.ConcurrentModificationException 高并发改动出现异常!
public class ListTest {
    public static void main(String[] args) {
        // 高并发下 ArrayList 不安全的吗,Synchronized;
        /*
         * 解决方法;
         * 计划方案1、List list = new Vector<>();
         * 计划方案2、List list =
         * Collections.synchronizedList(new ArrayList<>());
         * 计划方案3、List list = new CopyOnWriteArrayList<>();
         */
       /* CopyOnWrite 载入时拷贝  COW  电子计算机编程设计行业的一种优化策略;
        * 好几个进程启用的情况下,list,载入的情况下,固定不动的,载入(遮盖)
        * 在载入的情况下防止遮盖,导致数据信息难题!
        * 读写分离
        * CopyOnWriteArrayList  比 Vector Nb 在哪儿?
		*/	
        List list = new CopyOnWriteArrayList<>();

        for (int i = 1; i <= 10; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }

    }
}

CopyOnWriteArrayList源代码剖析参照

Set 不安全

**Set、Hash 等在高并发线程同步标准下,不可以完成信息共享,好几个进程另外启用一个set目标情况下便会发生高并发改动出现异常ConcurrentModificationException **。

编码举例说明:

package com.haust.unsafe;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
 * 同理可证 : ConcurrentModificationException 高并发改动出现异常
 * 1、Set set = 
 * 					Collections.synchronizedSet(new HashSet<>());
 * 2、
 */
public class SetTest {
    public static void main(String[] args) {
        //Set set = new HashSet<>();//不安全
        // Set set = Collections.synchronizedSet(new HashSet<>());//安全性
        Set set = new CopyOnWriteArraySet<>();//安全性

        for (int i = 1; i <=30 ; i++) {
           new Thread(()->{
               set.add(UUID.randomUUID().toString().substring(0,5));
               System.out.println(set);
           },String.valueOf(i)).start();
        }

    }
}

拓展:hashSet 最底层是啥?

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

能够看得出 HashSet 的最底层便是一个HashMap

在这里插入图片描述

HashMap源代码剖析参照

Map 不安全

回望Map操作过程:

在这里插入图片描述

编码举例说明:

package com.haust.unsafe;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

// ConcurrentModificationException
public class  MapTest {

    public static void main(String[] args) {
        // map 是那样用的吗? 并不是,工作上无需 HashMap
        // 默认设置等额的于哪些?  new HashMap<>(16,0.75);
        // Map map = new HashMap<>();
        // 拓展:科学研究ConcurrentHashMap的基本原理
        Map map = new ConcurrentHashMap<>();

        for (int i = 1; i <=30; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(),
                       UUID.randomUUID().toString().substring(0,5));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }
}

8、Callable (简易)

在这里插入图片描述

Callable 和 Runable 比照:

举例说明:例如Callable 就是你自身,你要根据你的女友 **Runable **了解她的好闺蜜 Thread

在这里插入图片描述

在这里插入图片描述

  • Callable 是 java.util 包下 concurrent 下的插口,有传参,能够抛出去被查验的出现异常
  • Runable 是 java.lang 包了的插口,沒有传参,不能抛出去被查验的出现异常
  • 二者启用的方式不一样,run()/ call()

一样的 LockSynchronized 二者的差别,前面一种是java.util 下的插口 后面一种是 java.lang 下的关键词。

编码举例说明

package com.haust.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 1、研究基本原理
 * 2、觉自身会用
 */
public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // new Thread(new Runnable()).start();// 运行Runnable
        // new Thread(new FutureTask()).start();
        // new Thread(new FutureTask( Callable )).start();
        new Thread().start(); // 怎么启动Callable?

        // new 一个MyThread案例
        MyThread thread = new MyThread();
        // MyThread案例放进FutureTask
        FutureTask futureTask = new FutureTask(thread); // 兼容类

        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start(); // call()方式結果会被缓存文件,提高工作效率,因而只复印一个call

        // 这一get 方式很有可能会造成堵塞!把他放进最终
        Integer o = (Integer) futureTask.get(); 
        // 或是应用异步通信来解决!
        System.out.println(o);// 1024
    }
}

class MyThread implements Callable {

    @Override
    public Integer call() {
        System.out.println("call()"); // A,B2个进程会复印好多个call?(一个)
        // 用时的实际操作
        return 1024;
    }
}

//class MyThread implements Runnable {
//
//    @Override
//    public void run() {
//        System.out.println("run()"); // 会复印好多个run
//    }
//}

关键点:

1、有缓存文件

2、結果很有可能必须等候,会堵塞!

9、常见的輔助类(必会)

9.1、CountDownLatch

在这里插入图片描述

加减法电子计数器: 完成启用几回进程后 再开启某一个每日任务

编码举例说明:

package com.haust.add;    

import java.util.concurrent.CountDownLatch;

// 电子计数器
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        // 数量是6,务必要执行任务的情况下,再应用!
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 1; i <=6 ; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()
                                   						+" Go out");
                countDownLatch.countDown(); // 总数-1
            },String.valueOf(i)).start();
        }

        countDownLatch.await(); // 等候电子计数器归零,随后再往下实行

        System.out.println("Close Door");

    }
}

基本原理:

countDownLatch.countDown(); // 总数-1

countDownLatch.await(); // 等候电子计数器归零,随后再往下实行

每一次有进程启用 countDown() 总数-1,假定电子计数器变成0,countDownLatch.await() 便会被唤起,执行!

9.2、CyclicBarrier

在这里插入图片描述

加减法电子计数器集满7颗七龙珠开宝箱

编码举例说明:

package com.haust.add;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class  CyclicBarrierDemo {
    public static void main(String[] args) {
        /*
         * 集满7颗七龙珠开宝箱
         */
        // 招唤七龙珠的进程
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("开宝箱取得成功!");
        });

        for (int i = 1; i <=7 ; i++) {
            final int temp = i;
            // lambda能实际操作到 i 吗
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()
                                   			  +"搜集"+temp+"个七龙珠");
                try {
                    cyclicBarrier.await(); // 等候
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

9.3、Semaphore

Semaphore:信号量

在这里插入图片描述

过流保护/抢车位!6车—3个泊车部位

编码举例说明:

package com.haust.add;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreDemo {
    public static void main(String[] args) {
        // 进程总数:停车场! 过流保护!、
        // 假如现有3个进程实行(3个停车位已满),则别的进程必须等候‘停车位’释放出来后,才可以实行!
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i <=6 ; i++) {
            new Thread(()->{
                // acquire() 获得
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread()
                                       		.getName()+"抢到停车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread()
                                       		.getName()+"离去停车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release(); // release() 释放出来 
                }

            },String.valueOf(i)).start();
        }
    }
}

仅有三个停车位,仅有当某一辆车离去停车位,停车位空出去后,下一辆车才可以在这里停车。

輸出結果如图所示:

在这里插入图片描述

基本原理:

semaphore.acquire(); 得到,假定假如早已满了,等候,等候被释放出来截止!semaphore.release(); 释放出来,会将当今的信号量释放出来 + 1,随后唤起等候的进程!

功效: 好几个资源共享相互独立的应用!高并发过流保护,操纵较大 的线程数!

10、读写锁 ReadWriteLock

ReadWriteLock

在这里插入图片描述

编码举例说明:

package com.haust.rw;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 独享锁(写锁) 一次只有被一个进程占据
 * 共享资源锁(读锁) 好几个进程能够另外占据
 * ReadWriteLock
 * 读-读  能够并存!
 * 读-写  不可以并存!
 * 写-写  不可以并存!
 */
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        //MyCache myCache = new MyCache();
        MyCacheLock myCacheLock = new MyCacheLock();

        // 载入
        for (int i = 1; i <= 5 ; i++) {
            final int temp = i;
            new Thread(()->{
                myCacheLock.put(temp+"",temp+"");
            },String.valueOf(i)).start();
        }

        // 载入
        for (int i = 1; i <= 5 ; i++) {
            final int temp = i;
            new Thread(()->{
                myCacheLock.get(temp+"");
            },String.valueOf(i)).start();
        }
    }
}

/**
 * 自定缓存文件
 * 上锁的
 */
class MyCacheLock{

    private volatile Map map = new HashMap<>();
    // 读写锁: 更为粗粒度的操纵
    private ReadWriteLock readWriteLock = new 			
        							ReentrantReadWriteLock();
    // private Lock lock = new ReentrantLock();

    // 存,载入的情况下,只期待另外只有一个进程写
    public void put(String key,Object value){
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()
                               						+"载入"+key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()
                               						+"载入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    // 取,读,任何人都能够读!
    public void get(String key){
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()
                               						+"载入"+key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()
                               						+"载入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }

}

/**
 * 自定缓存文件
 * 不上锁的
 */
class MyCache{

    private volatile Map map = new HashMap<>();

    // 存,写
    public void put(String key,Object value){
        System.out.println(Thread.currentThread().getName()
                           							+"载入"+key);
        map.put(key,value);
        System.out.println(Thread.currentThread().getName()
                           							+"载入OK");
    }

    // 取,读
    public void get(String key){
        System.out.println(Thread.currentThread().getName()
                           							+"载入"+key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()
                           							+"载入OK");
    }
}

实行实际效果如图所示:

在这里插入图片描述

在这里插入图片描述

11、阻塞队列

在这里插入图片描述

阻塞队列:

在这儿添加图片叙述

在这里插入图片描述

BlockingQueue

BlockingQueue 并不是新的物品

在这里插入图片描述

什么情况大家会应用 阻塞队列?:线程同步高并发解决,线程池用的较多 !

学好应用序列

加上、清除

四组API

方法抛出异常有传参,不抛出异常堵塞 等候请求超时等候
加上addoffer()put()offer(,)
清除removepoll()take()poll(,)
检验队首原素elementpeek()--

编码实例:

package com.kuang.bq;

import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        test4();
    }
    /**
     * 1. 无传参,抛出异常的方法
     */
    public static void test1(){
        // 序列的尺寸
        ArrayBlockingQueue blockingQueue = 
            						new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.add("a"));// true
        System.out.println(blockingQueue.add("b"));// true
        System.out.println(blockingQueue.add("c"));// true
        // System.out.println(blockingQueue.add("d"));
		// IllegalStateException: Queue full 抛出异常---序列已满!
        System.out.println("===========================");

        System.out.println(blockingQueue.element());//
        // 查询队首原素到底是谁
        System.out.println(blockingQueue.remove());//

        System.out.println(blockingQueue.remove());//
        System.out.println(blockingQueue.remove());//

        // System.out.println(blockingQueue.remove());
        // java.util.NoSuchElementException 抛出异常---序列已为空!
    }

    /**
     * 2. 有传参,不抛出异常的方法
     */
    public static void test2(){
        // 序列的尺寸
        ArrayBlockingQueue blockingQueue = 
            						new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));

        System.out.println(blockingQueue.peek());

        // System.out.println(blockingQueue.offer("d")); 
        // false 不抛出异常!
        System.out.println("===========================");
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll()); 
        // null  不抛出异常!
    }

    /**
     * 3. 等候,堵塞(一直堵塞)
     */
    public static void test3() throws InterruptedException {
        // 序列的尺寸
        ArrayBlockingQueue blockingQueue = 
            						new ArrayBlockingQueue<>(3);

        // 一直堵塞
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        // blockingQueue.put("d"); // 序列沒有部位了,一直堵塞等候
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take()); 
        // 沒有这一原素,一直堵塞等候

    }


    /**
     * 4. 等候,堵塞(等候请求超时)
     */
    public static void test4() throws InterruptedException {
        // 序列的尺寸
        ArrayBlockingQueue blockingQueue = 
            						new ArrayBlockingQueue<>(3);

        blockingQueue.offer("a");
        blockingQueue.offer("b");
        blockingQueue.offer("c");
        // blockingQueue.offer("d",2,TimeUnit.SECONDS); 
        // 等候超出2秒就撤出
        System.out.println("===============");
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        blockingQueue.poll(2,TimeUnit.SECONDS); // 等候超出2秒就撤出

    }
}

SynchronousQueue

SynchronousQueue 同歩序列

沒有容积,进来一个原素,务必等候取下来以后,才可以再往里放一个原素!

put、take

编码举例说明:

package com.haust.bq;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * 同歩序列:
 * 和别的的BlockingQueue 不一样, SynchronousQueue 不储存原素
 * put了一个原素,务必从里边先take取下来,不然不可以在put进来值!
 */
public class SynchronousQueueDemo {
    public static void main(String[] args) {
        BlockingQueue blockingQueue = 
            					new SynchronousQueue<>(); // 同歩序列

        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()
                                   						+" put 1");
                // put进到一个原素
                blockingQueue.put("1");
                System.out.println(Thread.currentThread().getName()
                                   						+" put 2");
                blockingQueue.put("2");
                System.out.println(Thread.currentThread().getName()
                                   						+" put 3");
                blockingQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"T1").start();


        new Thread(()->{
            try {
                // 睡眠质量三秒取下一个原素
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()
                                   		+"=>"+blockingQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()
                                   		+"=>"+blockingQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()
                                   		+"=>"+blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"T2").start();
    }
}

实行結果如下图所示:

在这里插入图片描述

12、线程池(关键)

线程池:3大方式、7大主要参数、4种回绝对策

池化技术性

程序流程的运作,实质:占有系统软件的資源! (提升資源的应用 => 池化技术性)

线程池、数据库连接池、内存池、目标池///… 建立、消毁。十分破坏环境

池化技术性:事前准备好一些資源,有些人得用,就来我这里拿,用完以后还给我。

线程池的益处:

  • 1、减少服务器资源的耗费

  • 2、提升回应的速率

  • 3、便于管理

进程多路复用、能够操纵较大 并发数、管理方法进程

线程池:3大方式

线程池:3大方式

在这里插入图片描述

实例编码:

package com.haust.pool;

import java.util.concurrent.ExecutorService;
import java.util.List;
import java.util.concurrent.Executors;

public class Demo01 {
    public static void main(String[] args) {
        // Executors java工具、3大方式
        // Executors.newSingleThreadExecutor();// 建立多带带进程的线程池
        // Executors.newFixedThreadPool(5);// 建立一个固定不动尺寸的线程池
        // Executors.newCachedThreadPool();// 建立一个可伸缩式的线程池

        // 多带带进程的线程池
		ExecutorService threadPool = 	
            					Executors.newSingleThreadExecutor();
        try {
            for (int i = 1; i < 100; i++) {
                // 应用了线程池以后,应用线程池来建立进程
                threadPool.execute(()->{
                    System.out.println(
                        Thread.currentThread().getName()+" ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 线程池用完,程序流程完毕,关掉线程池
            threadPool.shutdown();
        }
    }
}

线程池:7大主要参数

7大主要参数

源代码剖析:

public static ExecutorService newSingleThreadExecutor() { 
    return new FinalizableDelegatedExecutorService (
        new ThreadPoolExecutor(
            1, 
            1,
			0L, 
            TimeUnit.MILLISECONDS, 
            new LinkedBlockingQueue())); 
}

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(
        5, 
        5, 
        0L, 
        TimeUnit.MILLISECONDS, 
        new LinkedBlockingQueue()); 
}

public static ExecutorService newCachedThreadPool() { 
    return new ThreadPoolExecutor(
        0, 
        Integer.MAX_VALUE, 
        60L, 
        TimeUnit.SECONDS, 
        new SynchronousQueue()); 
}

// 实质ThreadPoolExecutor() 

public ThreadPoolExecutor(int corePoolSize, // 关键线程池尺寸 
                          int maximumPoolSize, // 较大 关键线程池尺寸 
                          long keepAliveTime, // 请求超时没人启用便会释放出来 
                          TimeUnit unit, // 请求超时企业 
                          // 阻塞队列 
                          BlockingQueue workQueue, 
                          // 进程加工厂:建立进程的,一般 无需动
                          ThreadFactory threadFactory,  
                          // 回绝对策
                          RejectedExecutionHandler handle ) { 
    if (corePoolSize < 0 
        || maximumPoolSize <= 0 
        || maximumPoolSize < corePoolSize 
        || keepAliveTime < 0) 
        throw new IllegalArgumentException(); 
    if (workQueue == null 
        || threadFactory == null 
        || handler == null) 
        throw new NullPointerException(); 
    this.acc = System.getSecurityManager() == null 
        ? null : AccessController.getContext(); 
    this.corePoolSize = corePoolSize; 
    this.maximumPoolSize = maximumPoolSize; 
    this.workQueue = workQueue; 
    this.keepAliveTime = unit.toNanos(keepAliveTime); 
    this.threadFactory = threadFactory; 
    this.handler = handler; 
}

在这里插入图片描述

在这里插入图片描述

手动式建立一个线程池

由于具体开发设计中java工具Executors 不安全,因此 必须手动式建立线程池,自定七个主要参数。

实例编码:

package com.haust.pool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

// Executors java工具、3大方式
// Executors.newSingleThreadExecutor();// 建立一个多带带进程的线程池
// Executors.newFixedThreadPool(5);// 建立一个固定不动尺寸的线程池
// Executors.newCachedThreadPool();// 建立一个可伸缩式的线程池

/**
 * 四种回绝对策:
 *
 * new ThreadPoolExecutor.AbortPolicy() 
 * 金融机构满了,也有人进去           
              
                             
评论
  • 消灭零回复