【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());
    }
    
    在这里怎么将第一种参数赋值进来??
        

Java线程池是一种用于管理和复用线程的机制。它可以在需要执行任务时,从线程池中获取可用的线程来执行任务,而不是每次都创建新的线程。这样可以减少线程创建和销毁的开销,提高系统的性能和资源利用率。 Java线程池通常由一个线程池管理器、工作队列和一组工作线程组成。线程池管理器负责创建、初始化和释放线程池,工作队列用于存储待执行的任务,工作线程则负责从队列中取出任务并执行。 使用线程池可以带来以下好处: 1. 提高系统性能:通过复用线程,降低了线程创建和销毁的开销,提高了系统的响应速度。 2. 控制资源消耗:通过限制线程的数量,可以控制系统同时运行的线程数量,避免资源过度消耗。 3. 提高系统稳定性:通过合理配置线程池参数,可以避免因为系统资源耗尽而导致系统崩溃。 在Java中,可以使用java.util.concurrent包中的Executor框架来创建和管理线程池。常用的线程池类型有FixedThreadPool、CachedThreadPool、SingleThreadExecutor等,每种类型适用于不同的场景和需求。 要使用线程池,通常需要以下步骤: 1. 创建线程池对象,并指定线程池的类型和参数。 2. 创建任务(Runnable或Callable对象)并提交给线程池。 3. 线程池会根据任务的类型和当前线程池状态,决定是创建新线程、复用现有线程,还是将任务加入到工作队列中。 4. 线程池中的工作线程会不断从队列中获取任务,并执行任务的run方法。 5. 当不再需要执行任务时,需要关闭线程池,释放资源。 通过合理使用线程池,可以有效管理线程,提高系统的性能和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值