【java线程】线程池学习

线程池

1、线程池的优势
1、降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁操作的消耗。
2、提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
3、提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调控和监控。
2、线程池参数
corePoolSize(必须):核心线程数。默认情况下,核心线程会一直存活,但是当将AllowCoreThreadTimeout设置为true时,核心线程也会超时回收。
maximumPoolSize(必须):线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。
keepAliveTime(必须):线程闲置超时时长。如果超过该时长,非核心线程就会被回收
unit(必须):指定keepAliveTime参数得到时间单位。常用的有:
workQueue(必须):任务队列。通过线程池的execute()方法提交的Runnable对象将存储在该参数中,其采用阻塞队列实现。
threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。
handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。

img

2.1 任务队列(workQueue)
任务队列是基于阻塞队列实现的,即采用生产者消费者模式
ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列
LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列,在未指明容量时,容量默认Integer.MAX_VALUE
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列
DelayQueue:是二叉堆实现的无界优先级阻塞队列,要求元素都实现Delayed接口,按照时延从队列中提取任务
SynchronousQueue:一个不存储元素的阻塞队列,消费者线程调用take方法的时候回发生阻塞,知道有一个生产者生产一个元素,消费者拿到并返回;生产者调用put方法也会阻塞,直到消费者消费一个元素,才会返回
LinkedBlockingQueue:使用双向队列实现的有界双端阻塞队列
LinkedTransferQueue:和LinkedBlockingQueue行为一致,但是是无界的阻塞队列
2.2 线程工厂(threadfactory)
线程工厂指定创建线程的方式,需要实现ThreadFactory接口,并实现newThread(Runnale r) 方法
2.3 拒绝策略
当线程池的线程数达到最大线程数时,需要执行拒绝策略。
AbortPolicy(默认): 丢弃任务并抛出异常
CallerRunsPolicy:由调用线程处理该任务
DiscardPolicy:丢弃任务,但是不抛出异常。
DiscardOldestPolicy:丢弃队列最早的未处理任务
3、功能线程池
定长线程池(FixedThreadPool):
	只有核心编程,线程数量固定,执行完立即回收,任务队列为链表结构的有界队列
	应用场景--控制线程最大并发数
定时线程池(ScheduledThreadPool):
	核心线程数固定,非核心线程数量无限,执行完闲置10ms后回收,任务队列为延时阻塞队列
	应用场景--执行定时或者周期性任务
可缓存线程池(CachedThreadPool):
	无核心线程,非核心线程数量无限,执行完闲置60s后回收,任务队列为不存储元素的阻塞队列
	应用场景--执行大量,耗时少的任务
单线程化线程池(SingleThreadExecutor):
	只有一个核心线程,无非核心线程,执行完立即回收,任务队列为链表结构的有界队列
    应用场景--不适合并发单可能引起IO阻塞性及影响UI线程相应的操作,如数据库操作、文件操作等
4、线程池创建
4.1 定长线程池(newFixedThreadPool)
创建一个线程
package com.example.demo.threadTest;

/**
 * @Author zhangxin
 * @Date 2021/7/14 8:56
 * @Version 1.0
 */
public class RunnableDemo implements Runnable{
    private int i;

    public RunnableDemo(int i) {
        this.i = i;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("当前线程名称:" + Thread.currentThread().getName() + "参数:" + i);
    }
}

package com.example.demo.threadTest;

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

/**
 * @Author zhangxin
 * @Date 2021/7/14 9:00
 * @Version 1.0
 */
public class NewFixedThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            newFixedThreadPool.execute(new RunnableDemo(i));
        }
        newFixedThreadPool.shutdown();
    }
}

4.2 定时线程池(newScheduledThreadPool)
scheduleAtFixedRate
(	Runnable command,  要执行的任务
	long initialDelay,  延迟第一次执行的时间
	long delay,         一个执行终止与下一个执行的开始之间的延迟
	TimeUnit unit		initialDelay和delay参数的时间单位
)
scheduleWithFixedDelay()同上


package com.example.demo.threadTest;

import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @Author zhangxin
 * @Date 2021/7/14 9:19
 * @Version 1.0
 */
public class NewScheduledThreadPoolTest {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);

        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                long start = System.currentTimeMillis();
                System.out.println("当前线程:" + Thread.currentThread().getName() + ", scheduled线程开始执行:"
                + DateFormat.getTimeInstance().format(new Date()));

                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                long end = System.currentTimeMillis();

                System.out.println("当前线程:" + Thread.currentThread().getName() + ",花费时间:" +
                        (end - start) / 1000 + "s");
                System.out.println("当前线程:" + Thread.currentThread().getName() + ", 线程结束:" +
                        DateFormat.getTimeInstance().format(new Date()));
                System.out.println("******************************");
            }
        }, 1, 5, TimeUnit.SECONDS);
    }
}

4.3 可缓存线程池(newCachedThreadPool)
package com.example.demo.threadTest;

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

/**
 * @Author zhangxin
 * @Date 2021/7/14 9:50
 * @Version 1.0
 */
public class NewCachedThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int id = i;
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("当前线程:" + Thread.currentThread().getName() + " 参数:" + id);
                }
            });
        }
        cachedThreadPool.shutdown();
    }
}

4.4 单线程线程池(newSingleThreadExecutor)
package com.example.demo.threadTest;

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

/**
 * @Author zhangxin
 * @Date 2021/7/14 9:59
 * @Version 1.0
 */
public class NewSingleThreadExecutorTest {
    public static void main(String[] args) {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int id = i;
            singleThreadExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("当前线程:" + Thread.currentThread().getName() + " 参数:" + id);
                }
            });
        }
        singleThreadExecutor.shutdown();
    }
}

5、问题汇总
public class NewFixedThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            final int id = i;
            newFixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("当前线程:" + Thread.currentThread().getName() + " 参数:" + id);
                }
            });
        }
        newFixedThreadPool.shutdown();
    }
为什么参数不能直接使用i,而要把i赋值给id之后再使用??
    
public class NewFixedThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            final int id = i;
            newFixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("当前线程:" + Thread.currentThread().getName() + " 参数:" + id);
                }
            });
            newFixedThreadPool.execute(new RunnableDemo());  【这里使用自己创建的线程】
        }
        newFixedThreadPool.shutdown();
    }
}

public class RunnableDemo implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("当前线程名称:" + Thread.currentThread().getName());
    }
    
    在这里怎么将第一种参数赋值进来??
        

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值