线程、进程、异步计算与线程池

线程和进程

1 进程&线程

1.1 进程

​ 进程本质上是一个运行的程序,是系统分配资源的基本单位,每一个进程都有一个独立的内存地址空间;(包括代码空间,数据空间),每一个进程内存空间,数据空间都是私有的, 不能被其他的进程访问;

也就是说进程与进程之间相互隔离的。

1.2 线程

线程是进程中一个任务,一个进程一个至少应该有一个线程(任务)。为了让 cpu 执行任务更加高效,提出了线程的任务执行方式。

进程中所有的资源都是被线程所共享的,线程是 cpu 分配的基本单位;(线程是 cpu 执 行的基本单元),线程之间操作共享资源来进行通信,线程共享进程的资源比进程通信更加 简单,高效。

1) 上下文切换

​ 现在服务器资源: 多核心的 cpu 资源,操作系统调度时候运行很多的进程,支持远大于 cpu 核心数的线程运行,操作系统如何分配 cpu 资源给多线程的呢?

image-20220117111230704

CPU 采用时间分片的模式将 cpu 的时间片段轮流分配给多个线程执行;分配每一个线程的时 间大概就是几十 ms, 线程在 cpu 时间片执行,如果当前线程没有执行结束,cpu 时间分片已 经结束,此线程就会别挂起,下一个 cpu 时间分片将会分配给下一个线程,上一个线程等待 被唤醒。

image-20220117111931583

​ 问题:线程没有执行完毕,线程别挂起,等待下次被唤醒,继续完成任务!系统是怎么知道 线程之前运行到哪里?从哪里开始执行呢??

​ CPU : 寄存器 (存储数据状态信息)

​ 程序计数器: 存储 cpu 正在执行的指令,执行下一条指令位置

​ Cpu 在执行任务时候,都必须依赖寄存器,程序计数器;这些东西就是 cpu 切换的开销;称 之为上下文切换

2)线程的调度

问题: 操作系统如何共享 cpu 时间分片,分配 cpu 执行权限? 线程何时分片到时间分片?

线程分配多长时间??重要的线程分配时间多一些? 次要的线程分配时间少一些??

(1)、抢占式调度

并发线程模式下,所有的线程都会抢占时间分片,获取执行权限。有些线程执行时间长, 造成线程阻塞等待,等待 cpu 资源;

image-20220117111340989

JVM 线程调度:抢占式调度模式

绝大多数的操作系统都采用的是抢占式调度

(2)、协同式调度

​ 一个线程执行完成后主动通知系统切换到另一个线程执行;(同步阻塞),致命缺点: 一个 线程阻塞,导致整个进程阻塞,一个线程异常,导致整个程序崩溃。

有很大的潜在风险

3)、并行,并发
(1)、并发: 一段时间内,多个线程轮流分配时间分片,抢占式执行。这就叫做并发;

image-20220117135517434

(2)、并行:同一时刻,多个线程同时执行;这就叫做并行执行;

image-20220117135548460

2多线程实现方式

1继承 Thread 类,实现多线程

package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/14:11
 * @Description:
 **/
public class testThread {
    public static void main(String[] args) {
        System.out.println("线程开始01继承Thread------start");
        //创建线程
        ThreadA threadA = new ThreadA();
        //开启线程
        threadA.run();
        System.out.println("线程开始01继承Thread-------end");

    }
    @Slf4j
    public static class ThreadA extends Thread{

        //线程的执行主体
        @Override
        public void run(){
            log.info("线程开始01继承Thread");
            //业务代码
            int i = 100 / 3;
            log.info("i =" + i + "  线程名字" + this.getName() + "  线程id" + this.getId());
        }
    }
}

继承Runnable方法实现多线程

2.1普通方法
package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/15:02
 * @Description:
 **/
public class TestThread02 {
    public static void main(String[] args) {
        //创建多线程对象
        ThreadB threadB = new ThreadB();
        //创建多线程对象
        Thread thread = new Thread(threadB);
        thread.run();

    }
    @Slf4j
    public static class ThreadB implements Runnable{

        @Override
        public void run() {
            log.info("继承Runnable方法实现多线程");
            int i = 100 / 3;
            log.info("继承Runnable方法实现多线程的结果{}",i);
            //不能用this.getName和this.getId的方法获得相关参数

        }
    }
}

2.2匿名内部类
package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/15:02
 * @Description:
 **/
@Slf4j
public class TestThread02 {

    public static void main(String[] args) {
        //普通方法
        //创建多线程对象
        ThreadB threadB = new ThreadB();
        //创建多线程对象
        Thread thread = new Thread(threadB);
        thread.run();
        //匿名内部类的方法开启
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                log.info("---匿名内部类继承Runnable方法实现多线程");
                int i = 100 / 3;
                log.info("---匿名内部类继承Runnable方法实现多线程的结果{}",i);
                //不能用this.getName和this.getId的方法获得相关参数
            }
        };
        Thread thread1 = new Thread(runnable);
        thread1.run();


    }
    @Slf4j
    public static class ThreadB implements Runnable{

        @Override
        public void run() {
            log.info("继承Runnable方法实现多线程");
            int i = 100 / 3;
            log.info("继承Runnable方法实现多线程的结果{}",i);
            //不能用this.getName和this.getId的方法获得相关参数

        }
    }
}

image-20220117155548599

2.3 FunctionalInterface

可以使用lambda表达式的方法创建

package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/15:02
 * @Description:
 **/
@Slf4j
public class TestThread02 {

    public static void main(String[] args) {
        //普通方法
        //创建多线程对象
        ThreadB threadB = new ThreadB();
        //创建多线程对象
        Thread thread = new Thread(threadB);
        thread.run();
        //匿名内部类的方法开启
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                log.info("---匿名内部类继承Runnable方法实现多线程");
                int i = 100 / 3;
                log.info("---匿名内部类继承Runnable方法实现多线程的结果{}",i);
                //不能用this.getName和this.getId的方法获得相关参数
            }
        };
        Thread thread1 = new Thread(runnable);
        thread1.run();
        new Thread(()->{
            log.info("---FunctionalInterface继承Runnable方法实现多线程");
            int i = 100 / 3;
            log.info("---FunctionalInterface继承Runnable方法实现多线程的结果{}",i);
        }).run();


    }
    @Slf4j
    public static class ThreadB implements Runnable{

        @Override
        public void run() {
            log.info("继承Runnable方法实现多线程");
            int i = 100 / 3;
            log.info("继承Runnable方法实现多线程的结果{}",i);
            //不能用this.getName和this.getId的方法获得相关参数

        }
    }
}

image-20220117160937452

3.使用Callable + FutureTask 实现多线程

有回掉方法

jdk1.5 后:添加 callable 接口,实现多线程,相较于 Thread, runnable

接口没有返回值,但是 callable 接口是有返回值。

 @FunctionalInterface:支持lambda表达式
* public interface Callable<V> {
* 有泛型,只有一个方法call,call方法就是多线程执行业务主体,
* 方法执行完毕后有返回值,返回值的类型就是制定的泛型类型
* 疑问:多线程的执行必须和thread有关,callable接口和thread有什么关系??

image-20220117164615434

3.1普通方法
package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

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

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/16:22
 * @Description:
 * @FunctionalInterface:支持lambda表达式
 * public interface Callable<V> {
 * 有泛型,只有一个方法call,call方法就是多线程执行业务主体,
 * 方法执行完毕后有返回值,返回值的类型就是制定的泛型类型
 * 疑问:多线程的执行必须和thread有关,callable接口和thread有什么关系??
 **/
@Slf4j
public class TestThread03 {
    public static void main(String[] args) {

        System.out.println("------------------start---------------");
        ThreadC threadC = new ThreadC();
        FutureTask<Integer> futureTask = new FutureTask<>(threadC);
        Thread thread = new Thread(futureTask);
        thread.start();

        System.out.println("-----------------end----------------");
    }
    public static class ThreadC implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            log.info("实现callable方法实现多线程");
            int i = 100 / 3;
            log.info("实现callable方法实现多线程的结果{}",i);
            return i;
        }
    }
}

此时 System.out.println("-----------------end----------------");并不会等待线程执行完毕

image-20220117171919598

package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

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

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/16:22
 * @Description:
 * @FunctionalInterface:支持lambda表达式
 * public interface Callable<V> {
 * 有泛型,只有一个方法call,call方法就是多线程执行业务主体,
 * 方法执行完毕后有返回值,返回值的类型就是制定的泛型类型
 * 疑问:多线程的执行必须和thread有关,callable接口和thread有什么关系??
 **/
@Slf4j
public class TestThread03 {
    public static void main(String[] args) {

        System.out.println("------------------start---------------");
        ThreadC threadC = new ThreadC();
        FutureTask<Integer> futureTask = new FutureTask<>(threadC);
        Thread thread = new Thread(futureTask);
        thread.start();
        try {
            //同步阻塞必须等待异步线程执行结束后才能输出end
            Integer integer = futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }


        System.out.println("-----------------end----------------");
    }
    public static class ThreadC implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            log.info("实现callable方法实现多线程");
            int i = 100 / 3;
            log.info("实现callable方法实现多线程的结果{}",i);
            return i;
        }
    }
}

image-20220117171932791

3.2 匿名内部类
package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

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

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/17:20
 * @Description:
 **/
@Slf4j
public class TestThread03_1 {
    public static void main(String[] args) {
        System.out.println("----------start---------");
        FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                log.info("匿名内部类实现callable方法实现多线程");
                int i = 100 / 3;
                log.info("匿名内部类实现callable方法实现多线程的结果{}", i);
                return i;
            }
        });
        Thread thread = new Thread(task);
        thread.start();
        try {
            Integer integer = task.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("----------end---------");

    }
}

3.3lambda表达式
package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

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

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/20:09
 * @Description:
 **/
@Slf4j
public class TestThread03_2 {
    public static void main(String[] args) {
        System.out.println("---------------start------------------");
        FutureTask<Integer> futureTask = new FutureTask<>(() -> {
            log.info("匿名内部类实现callable方法实现多线程");
            int i = 100 / 3;
            log.info("匿名内部类实现callable方法实现多线程的结果{}", i);
            return i;
        });
        Thread thread = new Thread(futureTask);
        thread.start();
        try {
            Integer integer = futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("---------------end------------------");
    }
}

3.线程池

​ 项目开发中,不会使用上面 3 种线程的实现方式,因为上面 3 种线程实现方式无法控制线程,可能会造成系统资源耗尽,浪费系统资源,造成系统的性能下降;

​ 在企业业务开发中,必须使用线程池的方式,构建多线程;让线程充分利用,降低系统的资源的消耗。

问题: 为什么要使用线程池???(池化技术)–从实践出发------0 基础学架构------VIP 开课吧-秒杀项目实战

​ 我们需要执行一个 java 任务,可以直接 new Thread 来运行任务,

线程从创建到消耗经历那些过程??

1、创建 java 线程实例,线程是一个对象实例,堆内存中分配内存(创建线程需要消耗时间和内存)

2、执行 start 方式启动线程,操作系统为 Java 线程创建对应的内核线程,线程处于就绪状态(内核线程是操作系统的资源,创建需要时间和内存)

3、线程被操作系统 cpu 调度器选中后,线程开始执行(run 方法开始运行)

4、JVM 开始为线程创建线程私有资源:JVM 虚拟机栈*程序计数器(需要时间和内存)

5、线程运行过程中,cpu 上下文切换 (消耗时间,频繁切换,影响性能)

6、线程运行完毕,Java 线程被垃圾回收器回收 (销毁线程内存需要时间)

从线程执行的流程来看:

1、线程不仅是 java 对象,更是操作系的资源(创建线程,消耗线程都需要时间)

2、Java 线程的创建和运行都需要内存空间(线程数量太多,消耗很多内存)

3、cpu 上下文切换(线程数量一大,cpu 频繁切换)

线程池优势:

1、降低系统的资源的消耗

2、提供系统的响应速度

3、方便管理(线程复用,控制最大并发数,管理线程)

事先准备好一些资源,用人要用(业务系统要是有线程),就来我这里拿(线程池中获取),

用完之后不能销毁,必须还给我(线程池线程可复用性);

线程池的创建

创建单线程池
package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

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

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/23:10
 * @Description:
 **/
@Slf4j
public class ThreadPool {
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        //创建线程池对象,创建单个线程池对象
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        //线程执行
        try {
            executorService.execute(()->{
                log.info("ExcutorS创建线程的方式实现多线程.......");
                int i = 100 / 3;
                log.info("ExcutorS创建线程的方式实现多线程结果{}",i);
            });
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }
}

image-20220117233143109

创建指定线程数线程池
package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

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

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/23:10
 * @Description:
 **/
@Slf4j
public class ThreadPool {
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        //创建线程池对象,创建指定个数线程池对象,此处为2个线程的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //线程执行
        try {
            for (int j = 1; j<10;j++){
                executorService.execute(()->{
                    log.info("ExcutorS创建线程的方式实现多线程.......");
                    int i = 100 / 3;
                    log.info("ExcutorS创建线程的方式实现多线程结果{}",i);
                });
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }
}

image-20220117235803330

创建一个按照计划执行的线程池
package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

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

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/23:10
 * @Description:
 **/
@Slf4j
public class ThreadPool2 {
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        //创建线程池对象,创建一个按照计划执行的线程池
        ExecutorService executorService = Executors.newScheduledThreadPool(2);
        //线程执行
        try {
            for (int j = 1; j<10;j++){
                executorService.execute(()->{
                    log.info("ExcutorS创建线程的方式实现多线程.......");
                    int i = 100 / 3;
                    log.info("ExcutorS创建线程的方式实现多线程结果{}",i);
                });
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }
}

image-20220117235854018

创建自动增长的线程池
package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;

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

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/23:10
 * @Description:
 **/
@Slf4j
public class ThreadPool3 {
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        //创建线程池对象,创建自动增长的线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        //线程执行
        try {
            for (int j = 1; j<10;j++){
                executorService.execute(()->{
                    log.info("ExcutorS创建线程的方式实现多线程.......");
                    int i = 100 / 3;
                    log.info("ExcutorS创建线程的方式实现多线程结果{}",i);
                });
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }
}

image-20220118000034203

使用的是execute方式创建的线程池,没有返回值,如果需要返回值就需要commit

不建议使用execute的方式创建线程池

原因是以上的线程池创建的方式,当线程量一大后,可能造成无限制创

建线程,从而导致内存被占满,线程量大导致性能严重下降,甚至 OOM;

image-20220118085246431

image-20220118085257606

image-20220118085310587

image-20220118085316898

参数解析:

1、corePoolSize: 线程池核心线程数,初始化线程池时候,会创建 核心线程等待状态,核心线程不会被销毁,提供线程的复用;

2*、*maximumPoolSize: 最大线程数;核心线程用完了,必须新建线程 执行任务,但是新建的线程不能超过最大线程数;

3*、keepAliveTime:线程存活时间,除了核心线程以为* maximumPoolSize- corePoolSize)的线程存活时间;当线程处于空闲状态,

他可以活多久;

4*、*unit: 存活时间单位

5*、*workQueue:任务阻塞队列,任务可能会很多,线程就那么几个,因此可以把多余的任务放入队列进行缓冲,队列采用 FIFO 的,等待线程空闲, 再从队列取出任务执行;

6.threadFactory: 线程工厂,默认使用 defaultthreadFactory, 用来创建线程的,一般使用默认即可;

7.RejectedExecutionHandler: 线程池拒绝策略

正确的方式:

使用ThreadPoolExecute创建线程池

/**
 * Creates a new {@code ThreadPoolExecutor} with the given initial
 * parameters and default thread factory and rejected execution handler.
 * It may be more convenient to use one of the {@link Executors} factory
 * methods instead of this general purpose constructor.
 *
 * @param corePoolSize the number of threads to keep in the pool, even
 *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
 * @param maximumPoolSize the maximum number of threads to allow in the
 *        pool
 * @param keepAliveTime when the number of threads is greater than
 *        the core, this is the maximum time that excess idle threads
 *        will wait for new tasks before terminating.
 * @param unit the time unit for the {@code keepAliveTime} argument
 * @param workQueue the queue to use for holding tasks before they are
 *        executed.  This queue will hold only the {@code Runnable}
 *        tasks submitted by the {@code execute} method.
 * @throws IllegalArgumentException if one of the following holds:<br>
 *         {@code corePoolSize < 0}<br>
 *         {@code keepAliveTime < 0}<br>
 *         {@code maximumPoolSize <= 0}<br>
 *         {@code maximumPoolSize < corePoolSize}
 * @throws NullPointerException if {@code workQueue} is null
 */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}
Executors.defaultThreadFactory()

threadFactory: 线程工厂,默认使用 defaultthreadFactory, 用来创建线

程的,一般使用默认即可;

/**
 * The default thread factory
 */
static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}
RejectedExecutionHandler: 线程池拒绝策略

四种拒绝策略:

image-20220118091027048

(1)、AbortPolicy : 新任务直接被拒绝,抛出异常: RejectedExecutionException;

(2)、DisCardPolicy: 队列满了,新任务忽略不执行,直接丢弃,不会抛出异常

(3)、DisCardOldestPolicy: 队列满了,新任务尝试和等待最久的线程竞争,也不会抛出异常;抛弃任务队列中等待最久任务,新任务直接添加到队列中

(4)、CallerRunPolicy: 新任务来临后,直接使用调用者所在线程执行任务即可

使用ThreadPoolExecute创建线程,拒绝策略使用RejectedExecutionException

可以通过DefaultThreadFactory来命名线程池

package com.kkb.cubemall.juc;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @Author: zhaokj
 * @Date: 2022/01/17/23:10
 * @Description:
 **/
@Slf4j
public class ThreadPoolExecuteDemo {
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        //创建线程池对象,创建自动增长的线程池
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(
                Runtime.getRuntime().availableProcessors(),
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new java.util.concurrent.ThreadPoolExecutor.AbortPolicy());
        //线程执行
        try {
            for (int j = 1; j<20;j++){
                executorService.execute(()->{
                    log.info("ExcutorS创建线程的方式实现多线程.......");
                    int i = 100 / 3;
                    log.info("ExcutorS创建线程的方式实现多线程结果{}",i);
                });
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }
}

image-20220118101729940

设置线程系线程数的数量

设置线程系线程数的数量: 根据业务类型进行设置(cpu 密集型,Io 密集型)

如果 CPU 密集型任务(所有任务都在内存中执行:没有磁盘的读写): 建议线程池最大数量设置为 N(cpu 核心数量)+1

如果 IO 密集型任务(大量磁盘读写任务):如果有 IO 操作,cpu 此时处于空闲状态, 最大线程数应该设置:2N+1

最大线程数设置公式:

最大线程数 = (任务执行时间 / 任务 cpu 时间)*N

队列使用

在 Java 并发编程中,使用线程池,还必须使用任务队列,让任务在队列中进行缓冲;可以

线程执行防洪泄流的效果,提升线程池处理任务能力;

java.util.concurrent 接口 BlockingQueue

首先在线程池中使用的都是阻塞队列 存和放都会阻塞

image-20220118112611334

基于 Java 一些队列实现特性:

1、ArrayBlockingQueue : 基于数组实现的有界的阻塞队列 (有界的队列)

2、LinkedBlockingQueue: 基于链表实现的有界阻塞队列

3、PriorityBlockingQueue: 支持按照优先级排序的无界的阻塞的队列

4、DelayQueue: 优先级实现的无界阻塞队列

5、SynchronousQueue : 只存储一个元素,如果这个元素没有被消费,不能在向里面存储元素

6、LinkedTransferQueue: 基于链表实现的无界的阻塞队列

7、LinkedBlockingDeque: 基于链表实现的双向的无界阻塞的队列

如何选择一个合适的队列:建议必须使用有界队列

有界队列能增加系统的稳定性,根据需求设置大一些(可控设置); 如果设置为无界队列,遇到不可控的因素,可能会导致队列中的任务越来越多,出现 OOM,撑爆整个系统;

此时如果还想继续的提升性能就要开启下一个话题-----异步计算

**4 **异步计算

3.1 什么是异步

​ 异步调用实现一个不需要被等等的方法的返回值;让调用者继续执行(异步执行);在java 中,简单的讲就是开启另一个线程完成程序计算,使得调用者继续执行,不需要等等计算的结果,但是调用者任然需要获取线程的计算结果(不需要同步阻塞等待)。

image-20220118141652221

3.2 Future

Future 也是一个异步计算结果返回接口,目的获取返回值结果。但是 future 在获取返回值结构的时候,方法必须同步阻塞等待返回值结果。

 Get : 获取结果(等待,阻塞)

 Get(timeout) : 获取结果,指定等待时间

 Cancel : 取消当前任务**–从实践出发------0 基础学架构------VIP 开课吧-秒杀项目实战**

 isDone : 判断任务是否已经完成 (轮询)

futrure 对于结果获取不是很方便,只能通过同步阻塞的方式获取结果,或者是轮询的方式获取到结果;阻塞的方式获取返回值结果与异步的思想想违背,轮询方式又很占用 cpu 资源,也不能及时得到我们结果。

为了简化异步编程的复杂性,提升我们的编程效率就要用到了异步编排的结果

3.3异步编排

CompletableFuture 可以帮助我们简化异步编程复杂性,提供了函数式编程的能力,可以通 过回调函数的方式处理计算结果。

CompletableFuture 具有Future的特性,还实现了CompletionStage接口,具备CompletionStage接口的特性: 串行执行,并行执行,聚合(AND 聚合,OR 聚合)

public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {

1)串行关系执行

串行关系执行: then – 然后,也就是表示下一步,所以通常是一个串行的关系体现,then

后面的单词(比如 run/apply/accept)就是函数是接口中抽象方法名称;

串行关系执行: 利用上一步的执行结果,去进行下一步任务执行,任务执行具有先后顺序,

因此把这种操作叫做串行关系。

Run
public CompletionStage<Void> thenRun(Runnable action); 

public CompletionStage<Void> thenRunAsync(Runnable action);

public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor); 
Apply
public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);

public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn); 

public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn,Executor executor);
Accept
public CompletionStage<Void> thenAccept(Consumer<? super T> action);

public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);

public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor);
Compose
public <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);

public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn); 

public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor);

2)聚合 AND

Combine…… with …… 和 both…… and …… 都是要求两者都必须满足,也就是

and 且的关系。

public <U,V> CompletionStage<V> thenCombine (CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync (CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn); 
public <U,V> CompletionStage<V> thenCombineAsync (CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn, Executor executor);

3.4 异步开启

1)RunAsync:没有使用自定义线程池,没有返回值,默认使用的是ForkJoinPool线程池

@Slf4j
public class AsycFutureDemo {
    public static void main(String[] args) {
        log.info("主线程开始---------->start");
        //runAsync:实现异步编排,没有返回值
        //public static ComplateFuture<Void> runAsync(Runnable runnable);
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() ->{
            //返回值的泛型为void,说明不关注返回值
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
        });

        try {
            voidCompletableFuture.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        log.info("主线程开始---------->end");

    }
}

2)RunAsync:使用自定义线程池,没有返回值,默认使用的是Thread1线程池

@Slf4j
public class AsycFutureDemo {

    public static ThreadPoolExecutor executorService = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),
            5,
            3,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(3),
            Executors.defaultThreadFactory(),
            new java.util.concurrent.ThreadPoolExecutor.AbortPolicy());
    public static void main(String[] args) {
        //创建线程池对象,创建自动增长的线程池
        log.info("主线程开始---------->start");
        //runAsync:实现异步编排,没有返回值
        //public static ComplateFuture<Void> runAsync(Runnable runnable);
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() ->{
            //返回值的泛型为void,说明不关注返回值
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
        },executorService);

        try {
            voidCompletableFuture.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        log.info("主线程开始---------->end");

    }
}

3)supplyAsync

supplyAsync:实现异步编排,没有返回值
public static void main(String[] args) {
        //创建线程池对象,创建自动增长的线程池
        log.info("主线程开始---------->start");
        //supplyAsync:实现异步编排,没有返回值
        //public static ComplateFuture<Void> supplyAsync(Supplier<U> supplier);
        CompletableFuture<Integer> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //返回值的泛型为void,说明不关注返回值
            log.info("子线程开始---------->start");
            int i = 10 / 3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(), i);
            return i;
        });
        try {
            Integer integer = voidCompletableFuture.get();
            log.info("supplyAsync 运行结果{}",integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        log.info("主线程开始---------->end");

    }

4)thenRun

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //public static ComplateFuture<Void> supplyAsync(Supplier<U> supplier);
        //thenrun没有返回值,也不关心上一步的返回值,只和上一步的执行顺序有关
        //public ComplationStage<Void> thenRUN(Runnable action);
        log.info("主线程开始---------->start");
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        }).thenRun(() -> {
            log.info("thenrun开始运行---------->start");

        });
        voidCompletableFuture.get();
        log.info("主线程结束---------->end");

    }

image-20220307233134284

thenrun没有返回值,也不关心上一步的返回值,只和上一步的执行顺序有关

5)thenRunAsync

thenRunAsync没有返回值,也不关心上一步的返回值,只和上一步的执行顺序有关

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        //public static ComplateFuture<Void> supplyAsync(Supplier<U> supplier);
        //thenRunAsync没有返回值,也不关心上一步的返回值,只和上一步的执行顺序有关
        //public ComplationStage<Void> thenRunAsync(Runnable action);
        log.info("主线程开始---------->start");
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        }).thenRunAsync(() -> {
            log.info("thenRunAsync开始运行---------->start");

        });
        voidCompletableFuture.get();
        log.info("主线程结束---------->end");

    }

image-20220307233600288

6)thenApply

public ComplationStage thenApply(Function<?super T,?extends U> fn);

T 就是返回值类型,U就是参数类型

image-20220308215739043

public static void main(String[] args) throws ExecutionException, InterruptedException {
        //public static ComplateFuture<Void> supplyAsync(Supplier<U> supplier);
        //thenApply 没有返回值,返回值类型是U,跟上一步执行结果有关系,上一步执行结果会被当成参数传递给下一步,参数类型为T
        //public ComplationStage<Void> thenApply(Function<?super T,?extends U> fn);
        log.info("主线程开始---------->start");
        CompletableFuture<Long> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        }).thenApply((t) -> {
            log.info("thenRunAsync开始运行---------->start,t的值为:{}",t);
            long res = t * 8;
            log.info("thenApply异步计算的结果: {}",res);
            return res;
        });
        Long aLong = voidCompletableFuture.get();
        log.info("thenApply的结果:{}",aLong);
        log.info("主线程结束---------->end");

    }

image-20220308215812012

image-20220308220426577

7)thenAccept

public static ComplateFuture supplyAsync(Supplier supplier);
thenAccept:没有返回值,跟上一步执行结果有关系,上一步执行结果会被下一步消费,参数类型为T
public CompletionStage thenAccept(Comsumer<? super T> action);

public static void main(String[] args) throws ExecutionException, InterruptedException {
        //public static ComplateFuture<Void> supplyAsync(Supplier<U> supplier);
        //thenAccept:没有返回值,跟上一步执行结果有关系,上一步执行结果会被下一步消费,参数类型为T
        //2、public CompletionStage<Void> thenAccept(Comsumer<? super T> action);
        log.info("主线程开始---------->start");
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        }).thenAccept((t) -> {
            log.info("thenRunAsync开始运行---------->start,t的值为:{}",t);
            long res = t * 8;
            log.info("thenApply异步计算的结果: {}",res); //没有返回值
        });
        voidCompletableFuture.get();
        log.info("主线程结束---------->end");

    }

image-20220315214838488

8)thenCombine

public static ComplateFuture supplyAsync(Supplier supplier);
thenCombine
1。有返回值
2。thenCombine会把两个ComplateionStage的任务都执行完毕后,把两个任务的结果一块交给thenCombine去处理
public<U,V> CompletionStage thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V>)

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        //public static ComplateFuture<Void> supplyAsync(Supplier<U> supplier);
        //thenCombine
        //1。有返回值
        //2。thenCombine会把两个ComplateionStage的任务都执行完毕后,把两个任务的结果一块交给thenCombine去处理
        //public<U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V>)
        log.info("主线程开始---------->start");
        CompletableFuture<Integer> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /4;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        });
        CompletableFuture<Integer> voidCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        });
        CompletableFuture<Integer> integerCompletableFuture = voidCompletableFuture.thenCombine(voidCompletableFuture1, (u, t) -> {
            log.info("u的值{}:", u);
            log.info("t的值{}:", t);
            return u + t;

        });
        Integer integer = integerCompletableFuture.get();
        System.out.println(integer);
        log.info("主线程结束======end");

    }

image-20220316221852494

9)thenAcceptBoth

public static ComplateFuture supplyAsync(Supplier supplier);
thenAcceptBoth
1。没有返回值
2。thenAcceptBoth会把两个ComplateionStage的任务都执行完毕后,把两个任务的结果一块交给thenAcceptBoth去处理

public static void main(String[] args) {
        //public static ComplateFuture<Void> supplyAsync(Supplier<U> supplier);
        //thenAcceptBoth
        // 1。没有返回值
        //2。thenAcceptBoth会把两个ComplateionStage的任务都执行完毕后,把两个任务的结果一块交给thenAcceptBoth去处理
        //public<U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiFunction<? super T,? super U,action)
        log.info("主线程开始---------->start");
        CompletableFuture<Integer> voidCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /4;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        });
        CompletableFuture<Integer> voidCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        });
        //注意没有返回值
        CompletableFuture<Void> integerCompletableFuture = voidCompletableFuture1.thenAcceptBoth(voidCompletableFuture2, (t,u) -> {
            log.info("u的值{}:", u);
            log.info("t的值{}:", t);

        });
        integerCompletableFuture.get();
    
        log.info("主线程结束======end");
    }

image-20220322205842662

10)runAfterBoth

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //public static ComplateFuture<Void> supplyAsync(Supplier<U> supplier);
        //thenAfterBoth
        // 1。没有返回值
        //2。thenAcceptBoth会把两个ComplateionStage的任务都执行完毕后,才会执行下一步操作
        //public<U> CompletionStage<Void> runAfterboth(CompletionStage<?> other,Runnable action)
        log.info("主线程开始---------->start");
        CompletableFuture<Integer> voidCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /4;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        });
        CompletableFuture<Integer> voidCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        });
        //注意没有返回值
        CompletableFuture<Void> integerCompletableFuture = voidCompletableFuture1.runAfterBoth(voidCompletableFuture2, () -> {
            log.info("runAfterBoth开始---------->start");

        });
        integerCompletableFuture.get();
        log.info("主线程结束======end");
    }

image-20220323213519576

3) OR

关键次 either

1)applyToEither

public static void runAfterBoth(String[] args) throws ExecutionException, InterruptedException {
        //public static ComplateFuture<Void> supplyAsync(Supplier<U> supplier);
        //thenAfterBoth
        // 1。没有返回值
        //2。thenAcceptBoth会把两个ComplateionStage的任务都执行完毕后,才会执行下一步操作
        //public<U> Complete<Void> runAfterboth(CompletionStage<?> other,Runnable action)
        log.info("主线程开始---------->start");
        CompletableFuture<Integer> voidCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /4;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        });
        CompletableFuture<Integer> voidCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /3;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        });
        //注意没有返回值
        //利用applyToEither做合并操作,or的关系
        CompletableFuture<Void> integerCompletableFuture = voidCompletableFuture1.runAfterBoth(voidCompletableFuture2, () -> {
                       log.info("applyToEither子线程开始,f1和f2执行的快的一个是:---------->{}",v);

        });
        integerCompletableFuture.get();
        log.info("主线程结束======end");
    }

image-20220327111743998

异常处理

exceptionally、whenComplete、handle

1> exceptionally

public static void main(String[] args) throws ExecutionException, InterruptedException {
//      public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)
        log.info("主线程开始---------->start");
        CompletableFuture<Integer> voidCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /4;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        }).exceptionally((t)->{
            log.info("业务失败:{1}",t.getMessage());
            return null;
        });
        voidCompletableFuture1.get();
        log.info("主线程end..................");
    }

不产生异常正常执行业务逻辑

image-20220329213244637

捕获业务逻辑的异常

image-20220329214630853

​ 2)whenComplete

public static void main(String[] args) throws ExecutionException, InterruptedException {
//      public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action)
        log.info("主线程开始---------->start");
        CompletableFuture<Integer> voidCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /0;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        }).whenComplete((t,u)->{
            log.info("执行结果:{}",t);
            if (u!=null) {
                log.info("业务失败:{}", u.getMessage());
                
            }
        });
        voidCompletableFuture1.get();
        log.info("主线程end..................");
    }

image-20220329220441980

3)handle

 public static void main(String[] args) throws ExecutionException, InterruptedException {
//      public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
        //还可以处理执行结果
        //相当于 try{}finally{} : 对上一步执行结果进行处理,还可以处理异常任务
        log.info("主线程开始---------->start");
        CompletableFuture<Integer> voidCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
            log.info("子线程开始---------->start");
            int i = 10 /0;
            log.info("子线程开始---------->end 线程名称:{} 执行结果{}", Thread.currentThread().getName(),i);
            log.info("子线程future开始运行---------->start");

            return i;
        }).handle((t,u)->{
            log.info("执行结果:{}",t);
            int res = -1;
            if (u!=null) {
                log.info("业务失败:{}", u.getMessage());
            }else {
                res = t * 5;
            }
            return res;
        });
        Integer integer = voidCompletableFuture1.get();
        log.info("最终的执行结果:{}",integer);
        log.info("主线程end..................");
    }

有异常被捕获

image-20220329224500593

没有异常,可以对执行结果进行处理

image-20220329224610420

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值