java多线程与自定义线程池

1. 多线程的优缺点

优点:

  1. 提升cpu使用率
  2. 异步处理任务,提升响应速度

缺点:

  1. 开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
  2. 多线程之间存在数据共享问题,提高技术复杂度

 

2. java开启多线程

  • 继承Thread类,重写 run() 方法

  • 实现Runnable接口,重写 run() 方法

  • 实现Callable接口,重写 call() 方法

 

3. 线程池

“线程池”顾名思义,就是存放线程的池子,这个池子可以存放多少线程取决于采用哪种线程池,取决于有多少并发线程,有多少计算机的硬件资源。使用线程池最直接的好处就是:线程可以重复利用、减少创建和销毁线程所带来的系统资源的开销,提升性能(节省线程创建的时间开销,使程序响应更快)

 

4. JDK的4种的线程池(JDK1.5之后)

1.单个线程的线程池。

ExecutorService executorService = Executors.newSingleThreadExecutor();

核心线程数和最大线程数均设置为1,使用的队列是无界队列LinkedBlockingQueue

 

2.固定线程数的线程池

ExecutorService executorService = Executors.newFixedThreadPool(5);

这种线程池里面的线程被设计成存放固定数量的线程,具体线程数可以考虑为CPU核数*N(N可大可小,取决于并发的线程数,计算机可用的硬件资源等)。可以通过下面的代码来获取当前计算机的CPU的核数。

int processors = Runtime.getRuntime().availableProcessors();

 

3.任务相关的线程池

ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);

除了线程池的特性以外,可以实现循环或延迟任务,可用于实现任务调度

 

4.回收型线程池

ExecutorService executorService = Executors.newCachedThreadPool();

核心池大小为0,线程池最大线程数目为最大整型。使用的是阻塞队列SynchronousQueue。该线程池适合处理比较小的任务,如果任务处理时间较长,那么在不断提交任务的情况下,会导致严重的性能问题。

 

5. 自定义一个线程池

jdk的线程池虽好,但是阿里Java开发手册中强烈要求我们不允许使用Executors来创建线程池对象,而要通过ThreadPoolExecutor的方式。

先了解线程池相关的参数以及概念

1.ThreadPoolExecutor的参数

参数说明
corePoolSize核心线程数
maximumPoolSize最大线程数量
keepAliveTime存活时间
timeUnit时间单位
workQueue缓存线程的队列
threadFactory创建线程的工厂
rejectedExecutionHandler线程池满了的拒绝策略

 

线程池 - 核心线程数

cpu密集型任务,就需要尽量压榨cpu,参考值可以设为NCPU+1
IO密集型任务,参考值可以设置为2*NCPU

2.线程池的队列

JDK提供了7个阻塞队列。(也属于并发容器)

  1. ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
  2. LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
  3. PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
  4. DelayQueue:一个使用优先级队列实现的无界阻塞队列。
  5. SynchronousQueue:一个不存储元素的阻塞队列。
  6. LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
  7. LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

阻塞队列是一个在队列基础上又支持了两个附加操作的队列。

2个附加操作:

支持阻塞的插入方法:队列满时,队列会阻塞插入元素的线程,直到队列不满。
支持阻塞的移除方法:队列空时,获取元素的线程会等待队列变为非空。

 

3.线程池的拒绝策略

ThreadPoolExecutor默认有四个拒绝策略:

1、ThreadPoolExecutor.AbortPolicy() 直接抛出异常RejectedExecutionException

2、ThreadPoolExecutor.CallerRunsPolicy() 直接调用run方法并且阻塞执行

3、ThreadPoolExecutor.DiscardPolicy() 直接丢弃后来的任务

4、ThreadPoolExecutor.DiscardOldestPolicy() 丢弃在队列中队首的任务

当然可以自己继承RejectedExecutionHandler来写拒绝策略.

 

自定义线程池代码示例:

package com.example.demo.yuwen;

import java.util.concurrent.*;

public class MyThreadPool {

    /**
     * 核心线程数
     */
    private static final int CORE_SIZE = 5;

    /**
     * 最大线程数
     */
    private static final int MAX_SIZE = 10;

    /**
     * 核心线程数额外的线程存活时间(核心线程数不会杀死)
     */
    private static final int KEEP_LIVE_TIME = 60;

    /**
     * 线程池队列长度
     */
    private static final int QUEUE_SIZE = 256;

    private static final ThreadPoolExecutor THREAD_POOL_EXECUTOR = createPool();

    /**
     * 创建一个线程池
     *
     * @return ThreadPoolExecutor
     */
    public static ThreadPoolExecutor createPool() {
        return new ThreadPoolExecutor(CORE_SIZE, MAX_SIZE, KEEP_LIVE_TIME, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(QUEUE_SIZE), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    }

    /**
     * 提交任务
     *
     * @param task task
     * @return Future
     */
    public static Future submit(Callable task) {
        return THREAD_POOL_EXECUTOR.submit(task);
    }

}

 

package com.example.demo.yuwen;

import java.util.concurrent.Callable;

public class MyThread implements Callable {

    /**
     * 自己可以定义多个参数,使用构造方法赋值
     */
    private String yourParam;

    public MyThread(String yourParam) {
        this.yourParam = yourParam;
    }

    @Override
    public Object call() throws Exception {
        System.out.println("thread is work");
        return yourParam;
    }
}

测试代码:

package com.example.demo.yuwen;

import java.util.concurrent.Future;

public class Demo {

    public static void main(String[] args) throws Exception {
        Future ret = MyThreadPool.submit(new MyThread("china"));
        System.out.println(ret.get());
    }
}

 

结果如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值