线程池--JAVA

简介: 而线程池就是用来优化线程频繁创建和销毁的场景,减少线程创建、销毁的频率。

虽然线程是轻量级进程,但是如果当创建和销毁的的频率非常之高,那么它也就会消耗很多的资源。

而线程池就是用来优化线程频繁创建和销毁的场景,减少线程创建、销毁的频率。

ExecutorService

JAVA标准库为我们实现了线程池,ExecutorService是一个接口,线程池的创建并不像平常的接口实现那样直接new,而是使用了“工厂模式”。

publicstaticvoidmain(String[] args) {
//创建有4个线程的线程池ExecutorServiceservice=Executors.newFixedThreadPool(4);
//创建一个可以根据任务数量 来自行调整线程数量 的线程池ExecutorServiceservice1=Executors.newCachedThreadPool();
//创建含有一个线程的线程池ExecutorServiceservice2=Executors.newSingleThreadExecutor();
//创建一个含有3个线程的线程池,该线程池可以调度命令在给定时间后延迟运行ScheduledExecutorServiceservice3=Executors.newScheduledThreadPool(3);
}

image.gif

创建好了之后可以利用submit()方法来给里面添加任务

publicstaticvoidmain(String[] args) {
//创建有4个线程的线程池ExecutorServiceservice=Executors.newFixedThreadPool(4);
//添加5个任务for (inti=0; i<5; i++) {
inta=i;
service.submit(()->{
System.out.println(a);
        });
    }
}

image.gif

image.png

但是第四种创建线程池的方法有点特殊如果你想要实现延时执行任务就需要使用schedule()方法。

publicstaticvoidmain(String[] args) {
// 创建一个定时执行任务的线程池,设置核心线程数为3ScheduledExecutorServiceservice=Executors.newScheduledThreadPool(3);
//打印当前时间System.out.println(System.currentTimeMillis());
// 定时执行任务,延迟2秒后开始执行service.schedule(() -> {
// 执行的任务逻辑System.out.println("任务执行时间:"+System.currentTimeMillis());
        }, 2, TimeUnit.SECONDS);
}

image.gif

image.png

上述这几个创建线程池的方法本质上都是将ThreadPoolExecutor进行了封装。

ThreadPoolExecutor

这个类有4中构造方法,可是仔细看就会发现前三种还是调用的的四种,所以本质上是只有一种。

image.png

各个参数的含义

corePoolSize

当前线程池中的核心线程数即当前线程池在空闲时含有的线程数量,也就是当前线程池包含的线程最少数量。

maximumPoolSize

当前线程池中允许存在的最大线程数。

keepAliveTime

当实际线程数大于核心线程数时,多余的空闲线程能够存活的最长时间。

unit

存活时间的单位。

NANOSECONDS:千分之一微秒;

MICROSECONDS:千分之一毫秒;

MILLISECONDS:千分之一秒;

SECONDS:秒;

MINUTES:分钟;

HOURS:小时;

DAYS:天;

workQueue

用于保存待执行任务的队列。

threadFactory

创建新线程时所用的工厂类。

handler

当线程池中的任务满了之后所使用的拒绝策略。

ThreadPoolExecutor.AbortPolicy:直接抛出异常;

ThreadPoolExecutor.CallerRunsPolicy:新添加的任务,由添加任务的线程执行;

ThreadPoolExecutor.DiscardOldestPolicy :丢弃队列中最老的任务,再将新任务添加进任务队列;

ThreadPoolExecutor.DiscardPolicy:丢弃新添加的任务。

线程池的关闭

想要关闭线程池需要使用shutdown()方法

publicstaticvoidmain(String[] args) {
// 创建一个定时执行任务的线程池,设置核心线程数为3ScheduledExecutorServiceservice=Executors.newScheduledThreadPool(3);
//打印当前时间System.out.println(System.currentTimeMillis());
// 定时执行任务,延迟2秒后开始执行service.schedule(() -> {
// 执行的任务逻辑System.out.println("任务执行时间:"+System.currentTimeMillis());
    }, 2, TimeUnit.SECONDS);
}

image.gif

可以看出任务执行完后程序并没有退出。

image.png

publicstaticvoidmain(String[] args) {
// 创建一个定时执行任务的线程池,设置核心线程数为3ScheduledExecutorServiceservice=Executors.newScheduledThreadPool(3);
//打印当前时间System.out.println(System.currentTimeMillis());
// 定时执行任务,延迟2秒后开始执行service.schedule(() -> {
// 执行的任务逻辑System.out.println("任务执行时间:"+System.currentTimeMillis());
    }, 2, TimeUnit.SECONDS);
//主线程休眠一段时间try {
Thread.sleep(2000); // 休眠2秒    } catch (InterruptedExceptione) {
e.printStackTrace();
    }
// 关闭线程池service.shutdown();
}

image.gif

image.png

接下来为了更好的理解线程池,下面是模拟实现一个含有固定线程数的线程池。

模拟实现

先创建一个类名为MyThreadPool里面含有一个属性,类型为BlockingQueue。

publicclassMyThreadPool {
//队列大小为5privateBlockingQueue<Runnable>queue=newArrayBlockingQueue<>(5);
}

image.gif

写一个只有一个参数的有参构造方法,参数为线程池的线程数。

利用循环创建n个线程,每个线程都不断地从队列中拿任务。

publicMyThreadPool(Integern) {
for (inti=0; i<n; i++) {
Threadt=newThread(()->{
while(true) {
try {
Runnablerunnable=queue.take();
runnable.run();
                } catch (InterruptedExceptione) {
thrownewRuntimeException(e);
                }
            }
        });
t.start();
    }
}

image.gif

写一个submit()方法可以给队列中添加任务。

publicvoidsubmit(Runnablerunnable) {
try {
this.queue.put(runnable);
    } catch (InterruptedExceptione) {
thrownewRuntimeException(e);
    }
}

image.gif

此时一个简单的线程池就完成了,下面来进行一下简单的测试:

publicstaticvoidmain(String[] args) {
MyThreadPoolmyThreadPool=newMyThreadPool(5);
for (inti=0; i<40; i++) {
inta=i;
myThreadPool.submit(()->{
System.out.println(a);
        });
    }
}

image.gif

image.png

完整代码

importjava.util.concurrent.ArrayBlockingQueue;
importjava.util.concurrent.BlockingQueue;
//线程池publicclassMyThreadPool {
privateBlockingQueue<Runnable>queue=newArrayBlockingQueue<>(5);
publicMyThreadPool(Integern) {
for (inti=0; i<n; i++) {
Threadt=newThread(()->{
while(true) {
try {
Runnablerunnable=queue.take();
runnable.run();
                    } catch (InterruptedExceptione) {
thrownewRuntimeException(e);
                    }
                }
            });
t.start();
        }
    }
publicvoidsubmit(Runnablerunnable) {
try {
this.queue.put(runnable);
        } catch (InterruptedExceptione) {
thrownewRuntimeException(e);
        }
    }
}

image.gif


目录
相关文章
|
4天前
|
Java 测试技术
Java多线程的一些基本例子
【5月更文挑战第17天】Java多线程允许并发执行任务。示例1展示创建并启动两个`MyThread`对象,各自独立打印&quot;Hello World&quot;。示例2的`CounterExample`中,两个线程(IncrementThread和DecrementThread)同步地增加和减少共享计数器,确保最终计数为零。这些例子展示了Java线程的基本用法,包括线程同步,还有如Executor框架和线程池等更复杂的用例。
11 0
|
1天前
|
安全 Java 程序员
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第20天】本文将深入探讨Java并发编程的核心概念,包括线程安全和性能优化。我们将详细解析synchronized关键字、ReentrantLock类以及java.util.concurrent包中的高级工具类,如Semaphore、CountDownLatch和CyclicBarrier等。通过实例演示如何使用这些工具来提高多线程程序的性能和可靠性。
|
1天前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第20天】 在多核处理器日益普及的今天,并发编程成为了软件开发中不可忽视的重要话题。Java语言提供了丰富的并发工具和机制来帮助开发者构建高效且线程安全的应用程序。本文将探讨Java并发的核心概念,包括线程同步、锁机制、以及如何通过这些工具实现性能优化。我们将透过实例分析,揭示并发编程中的常见问题,并展示如何利用现代Java API来解决这些问题。
|
1天前
|
安全 Java 开发者
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第20天】在Java并发编程中,线程安全和性能优化是两个关键要素。本文将深入探讨Java并发编程的基本概念、线程安全的实现方法以及性能优化技巧。通过分析同步机制、锁优化、无锁数据结构和并发工具类的使用,我们将了解如何在保证线程安全的前提下,提高程序的性能。
|
1天前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第20天】 在Java开发中,正确处理并发问题对于确保应用的稳定性和提高性能至关重要。本文将深入探讨Java并发编程的核心概念——线程安全,以及如何通过各种技术和策略实现它,同时保持甚至提升系统性能。我们将分析并发问题的根源,包括共享资源的竞争条件、死锁以及线程活性问题,并探索解决方案如同步机制、锁优化、无锁数据结构和并发工具类等。文章旨在为开发者提供一个清晰的指南,帮助他们在编写多线程应用时做出明智的决策,确保应用的高效和稳定运行。
|
1天前
|
安全 Java
Java中的多线程编程:概念、实现及性能优化
【5月更文挑战第20天】在计算机科学中,多线程是一种允许程序同时执行多个任务的技术。Java作为一种广泛使用的编程语言,提供了对多线程编程的支持。本文将介绍Java中多线程的基本概念、实现方法以及性能优化策略,帮助读者更好地理解和应用多线程技术。
|
2天前
|
Java
Java一分钟之-并发编程:线程间通信(Phaser, CyclicBarrier, Semaphore)
【5月更文挑战第19天】Java并发编程中,Phaser、CyclicBarrier和Semaphore是三种强大的同步工具。Phaser用于阶段性任务协调,支持动态注册;CyclicBarrier允许线程同步执行,适合循环任务;Semaphore控制资源访问线程数,常用于限流和资源池管理。了解其使用场景、常见问题及避免策略,结合代码示例,能有效提升并发程序效率。注意异常处理和资源管理,以防止并发问题。
25 2
|
2天前
|
安全 Java 容器
Java一分钟之-并发编程:线程安全的集合类
【5月更文挑战第19天】Java提供线程安全集合类以解决并发环境中的数据一致性问题。例如,Vector是线程安全但效率低;可以使用Collections.synchronizedXxx将ArrayList或HashMap同步;ConcurrentHashMap是高效线程安全的映射;CopyOnWriteArrayList和CopyOnWriteArraySet适合读多写少场景;LinkedBlockingQueue是生产者-消费者模型中的线程安全队列。注意,过度同步可能影响性能,应尽量减少共享状态并利用并发工具类。
17 2
|
2天前
|
Java 程序员 调度
Java中的多线程编程:基础知识与实践
【5月更文挑战第19天】多线程编程是Java中的一个重要概念,它允许程序员在同一时间执行多个任务。本文将介绍Java多线程的基础知识,包括线程的创建、启动和管理,以及如何通过多线程提高程序的性能和响应性。
|
3天前
|
Java
深入理解Java并发编程:线程池的应用与优化
【5月更文挑战第18天】本文将深入探讨Java并发编程中的重要概念——线程池。我们将了解线程池的基本概念,应用场景,以及如何优化线程池的性能。通过实例分析,我们将看到线程池如何提高系统性能,减少资源消耗,并提高系统的响应速度。
13 5