Java线程池和反射

目录

线程池

一、Java构建线程的方法

二、线程池的7个参数

三、线程池的执行流程

四、线程池属性标识

五、线程池的 execute 方法执行

六、Worker的封装

七、线程执行的后续处理

反射


线程池

线程池ThreadPoolExecutor源码剖析

一、Java构建线程的方法

  • 实现Runnable
  • 继承Thread

        

  • 实现Callable
    • 有返回值return,可以抛出异常
  • 线程池方式
    • 优点:避免频繁创建线程和销毁线程带来的损耗
    • Java提供了构建线程池的的方式,用 Executors 可以去创建(但是规范中不允许使用这种方式创建线程池,这种方式对线程的控制力度比较低)
    • 推荐手动创建线程池

二、线程池的7个参数

Java线程池和反射_第1张图片

 七个参数:

参数 解释
corePoolSize 核心线程数
maximumPoolSize 最大线程数
keepAliveTime 最大空闲时间
TimeUnit 时间单位
BlockingQueue 阻塞队列
ThreadFactory 线程工厂
RejectedExecutionHandler 拒绝策略

三、线程池的执行流程

线程池的执行流程

 为什么要先进阻塞再去尝试创建非核心线程:

eg:饭店(线程池)--- 厨师(线程)---人多先排队(阻塞队列)---招厨师(创建最大线程数)---客满(拒绝策略)

四、线程池属性标识

4.1.核心属性

Java线程池和反射_第2张图片

 //是一个int类型的数值,表达了两个意思,1:声明当前线程池的状态,2:声明线程池中的线程数

//高3位:线程池状态  低29位:线程池中的线程个数

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//固定值,29,方便后面做位运算
private static final int COUNT_BITS = Integer.SIZE - 3;
//通过位运算得出最大容量
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;



// 线程池状态
//111  代表线程池为 RUNNING ,代表正常接收任务
private static final int RUNNING    = -1 << COUNT_BITS;
//000  代表线程池为 SHUTDOWN 状态,不接收新任务,但是内部还会处理阻塞队列中的任务,正在进行的任务也正常处理
private static final int SHUTDOWN   =  0 << COUNT_BITS;
//001  代表线程池为 STOP 状态,不接收新任务,也不去处理阻塞队列中的任务,同时会中断正在执行的任务     
private static final int STOP       =  1 << COUNT_BITS;
//010  代表线程池为 TIDYING 状态,过渡的状态,代表当前线程池即将Game over
private static final int TIDYING    =  2 << COUNT_BITS;
//011  代表线程池为 TERMINATED ,凉透了
private static final int TERMINATED =  3 << COUNT_BITS;

// 得到线程池的状态
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// 得到当前线程池的线程数量
private static int workerCountOf(int c)  { return c & CAPACITY; }

4.2.线程池状态变化

Java线程池和反射_第3张图片 线程池状态变化图

线程池的状态可以通过ThreadPoolExecutor类的getPoolSize()方法,getActiveCount()方法,getCompletedTaskCount()方法和getTaskCount()方法来查询。线程池的状态有以下几种:

1. Running(运行状态):线程池新建或调用execute()方法后,处于运行状态,能够接收新的任务。

2. Shutdown(关闭状态):线程池调用shutdown()方法后,线程池的状态会变为Shutdown。此时线程池不再接收新的任务,但会执行已提交的等待任务队列中的任务。

3. Stop(停止状态):人为调用shutdownNow()方法后,线程池的状态会变为Stop。此时线程池不再接收新的任务,并且会中断正在处理中的任务。

4. Tidying(整理状态):当线程池处于Shutdown或Stop状态时,如果等待队列中还有未执行的任务,则线程池将执行整理操作,将等待队列中的未执行任务移除,并保存到一个列表中。

5. Terminated(终止状态):当线程池处于Shutdown状态,并且等待队列中的任务全部执行完毕,或者在Stop状态下,线程池内部的所有线程都已经终止时,线程池进入Terminated状态。

线程池的状态变化如上所述,可以更好地对线程池进行管理和监控。
 

五、线程池的 execute 方法执行

从execute方法开始

public void execute(Runnable command) {
    //健壮性判断
    if (command == null)
        throw new NullPointerException();
    //拿到32位的int
    int c = ctl.get();
    //获取  工作线程数 < 核心线程数
    if (workerCountOf(c) < corePoolSize) {
        //进到if,代表可以创建核心线程数
        if (addWorker(command, true))
            //到这结束
            return;
        //如果if没进去,代表创建核心线程数失败,重新获取ctl 32位的int
        c = ctl.get();
    }
    //判断线程池是不是RUNNING,将任务添加到阻塞队列中的
    if (isRunning(c) && workQueue.offer(command)) {
        //再次获取ctl
        int recheck = ctl.get();
        //再次判断是否是RUNNING,  如果不是RUNNING,移除任务
        if (! isRunning(recheck) && remove(command))
            reject(command);//拒绝策略
        //如果线程处在 RUNNING 状态,但是工作线程为0
        else if (workerCountOf(recheck) == 0)

            addWorker(null, false);//阻塞队列有任务,但是没有工作线程,添加一个任务为空的工作线程处理阻塞队列中的任务
    }
    //创建非核心线程,处理任务
    else if (!addWorker(command, false))
        reject(command);//拒绝策略
}

通过上述源码,掌握了线程池的执行流程,再次查看 addWorker 方法内部做了什么处理。

private boolean addWorker(Runnable firstTask, boolean core) {
    //标记for循环   
    retry:
    for (;;) {

        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

六、Worker的封装

七、线程执行的后续处理


反射

什么时反射?

        反射允许对成员变量,成员方法和构造方法的信息进行编程访问。

Java线程池和反射_第4张图片

 

Java线程池和反射_第5张图片

Java线程池和反射_第6张图片

Java线程池和反射_第7张图片

 Java线程池和反射_第8张图片

 Java线程池和反射_第9张图片

--------------------------------------------------------------------------------------

  • 反射(Reflection)
    • 运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为 Java 语言的反射机制。
  • 深入理解
    • 反射使我们在运行时看清一个类的运行情况并使用
    • 反射是Java被视为动态或准动态语言的关键特性
    • 反射允许程序在运行时加载、探查、使用一个在编译期可能未知的类

-------------------------------------------------------------------------------

使用反射的步骤:

  • 获取想要操作的类的 Class 对象
  • 调用Class类中的方法
  • 使用反射API来操作这些信息

-------------------------------------------------------------------------------

Class类常用方法:

  • 获取属性
    • getFields() -所有可访问的公共字段
    • getDeclaredFields() -所有字段
    • getField(String name) -返回一个特定的公共字段对象
  • 获取方法
    • getMethods() -所有公共方法,包括从超类和超接口继承的声明
    • getDeclaredMethods() -所有方法,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法
    • getMethod(String name, Class[ ] parameterTypes) -返回一个方法对象
  • 获取构造方法
    • 获取构造方法
      • getConstructor(Class[] parameterTypes) -返回一个构造方法对象
    • 通过 Constructor-newInstance(Object[] initargs) 可生成类的实例
    • 通过Method-invoke(Object obj,Object[] args),可在具有指定参数的方法对象上调用此方法对象表示的基础方法

-------------------------------------------------------------------------------

反射优缺点

优点:

  • 运行期类型的判断,动态类加载
  • 提高了程序的灵活性、扩展性、降低耦合性
  • 提高自适应能力,无需提前硬编码目标类

缺点:

  • 性能问题
  • 安全限制
  • 内部暴露

反射应用场景

  • 反射机制是目前众多Java框架实现的基础
    • JDBC
    • Hibernate
    • Spring AOP、IoC
    • 分布式微服 
  • 实现项目安装插件功能
  • 基于反射,架构师搭建项目框架,自行封装框架,使得项目更加组件化和通用化

-------------------------------------------------------------------------------

总结

  • 什么是反射?
    • 关键点:运行状态、动态获取信息、生成类的实例以及动态调用对象 方法
  • 反射API(类及方法)
    • java.lang.class;
      • forName()、newInstance()
      • getFields()等、getMethods()等、getConstructor()
    • java.lang.reflect.Field;
      • getName()
    • java.lang.reflect.Method;
      • getName()、invoke()
    • java.lang.reflect.Constructor;
      • newInstancce()
  • 实操
    • 基于反射获取类信息(构造方法、属性、方法)
    • 基于反射生成类的实例
    • 基于反射动态调用对象方法

你可能感兴趣的:(Java核心编程API,java,开发语言,eclipse,java高级)