线程和线程池原理及demo演示

线程和线程池原理及demo演示

创建一个线程有两种方式:
1.继承Thread类
2.实现Runnable接口

但也带来了下面的问题:
创建和销毁一个线程,都是比较耗时,频繁的创建和销毁线程,非常影响系统的性能。
无限制的创建线程,会导致内存不足。
有新任务过来时,必须要先创建好线程才能执行,不能直接复用线程。

为了解决上面的这些问题,Java中引入了:线程池。
它相当于一个存放线程的池子。
使用线程池带来了下面3个好处:
1.降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2.提高响应速度。当任务到达时,可以直接使用已有空闲的线程,不需要的等到线程创建就能立即执行。
3.提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性。而如果我们使用线程池,可以对线程进行统一的分配、管理和监控。

线程池的构造器:

public ThreadPoolExecutor(
    int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler)

参数说明:
corePoolSize:核心线程数,线程池维护的最少线程数。
maximumPoolSize:最大线程数,线程池允许创建的最大线程数。
keepAliveTime:线程存活时间,当线程数超过核心线程数时,多余的空闲线程的存活时间。
unit:时间单位。
workQueue:任务队列,用于保存等待执行的任务。
threadFactory:线程工厂,用于创建新线程。
handler:拒绝策略,当任务无法执行时的处理策略。


线程池的工作过程如下:
1.线程池初始化:根据corePoolSize初始化核心线程。
2.任务提交:当任务提交到线程池时,根据当前线程数判断:
3.若当前线程数小于corePoolSize,创建新的线程执行任务。
4.若当前线程数大于或等于corePoolSize,任务被加入workQueue队列。
5.任务处理:当有空闲线程时,从workQueue中取出任务执行。
6.线程扩展:若队列已满且当前线程数小于maximumPoolSize,创建新的线程处理任务。
7.线程回收:当线程空闲时间超过keepAliveTime,多余的线程会被回收,直到线程数不超过corePoolSize。
8.拒绝策略:若队列已满且当前线程数达到maximumPoolSize,则根据拒绝策略处理新任务。

package com.example.core.mydemo.thread;

import java.util.concurrent.*;

public class ExecutorServiceTest {
    public static void main(String[] args) {
        /**
         * 设置10个线程
         * 队列过大
         * 如果向newFixedThreadPool线程池中提交的任务太多,可能会导致LinkedBlockingQueue非常大,从而出现OOM问题。
         */
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        /**
         *
         */
        ExecutorService executorService2 = Executors.newSingleThreadExecutor();
        /**
         * 线程太多
         * 如果向newCachedThreadPool线程池中提交的任务太多,可能会导致创建大量的线程,也会出现OOM问题。
         */
        ExecutorService executorService3 = Executors.newCachedThreadPool();

        //自定义线程 ThreadPoolExecutor
        /**
         * 上面的OOM问题,我们在日常开发中,可以通过自定义线程池的方式解决。
         * 自定义了一个最大线程数量和任务队列都在可控范围内线程池。
         */
        ThreadPoolExecutor executorService4 = new ThreadPoolExecutor(8,
                10,
                30L,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(300));

        ScheduledExecutorService scheduledExecutorService5 = Executors.newScheduledThreadPool(2);

        /**
         * 线程运行
         * Thread Name: pool-1-thread-1time:2024-09-18T18:10:01.417
         */
        executorService.submit(new MyRunnable());

        /**
         * 线程运行
         * Thread Name: pool-2-thread-1time:2024-09-18T18:09:29.972
         */
//        executorService2.submit(new MyRunnable());

        /**
         * Thread Name: pool-3-thread-1time:2024-09-18T18:08:55.597
         */
//        executorService3.submit(new MyRunnable());
//
        /**
         * 线程运行
         * Thread Name: pool-4-thread-1time:2024-09-18T18:08:30.520
         */
//        executorService4.submit(new MyRunnable());
//
        /**
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T18:08:03.031
         */
//        scheduledExecutorService5.submit(new MyRunnable());
        /**
         * 单词执行:线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T18:07:14.710
         */
//        scheduledExecutorService5.execute(new MyRunnable());

        /**
         * link: 使用ScheduledExecutorService代替下Timer
         * https://www.cnblogs.com/oktokeep/p/17000649.html
         */
        /**
         * output: 执行5s,等待4s,所以间隔是9s
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T17:58:33.861
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T17:58:42.862
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T17:58:51.864
         */
//        scheduledExecutorService5.scheduleWithFixedDelay(new MyRunnable(),1,4, TimeUnit.SECONDS);

        /**
         * output:执行5s,等待0s(立即执行),所以间隔是5s
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T17:59:44.928
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T17:59:49.928
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T17:59:54.929
         */
        /**
         * output:执行3s,等待:(4-3=1s),所以间隔是4s
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T18:00:43.648
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T18:00:47.612
         * 线程运行
         * Thread Name: pool-5-thread-1time:2024-09-18T18:00:51.612
         */
//        scheduledExecutorService5.scheduleAtFixedRate(new MyRunnable(),1,4, TimeUnit.SECONDS);
    }
}



package com.example.core.mydemo.thread;

import java.time.LocalDateTime;

/**
 * class Thread implements Runnable {
 * main Thread Name: main
 * 线程运行
 * Thread Name: Thread-0time:2024-11-19T15:38:07.668
 */
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("线程运行");
        Thread currentThread = Thread.currentThread();
        System.out.println("Thread Name: " + currentThread.getName() + "time:" + LocalDateTime.now());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        MyRunnable myThread = new MyRunnable();
//        myThread.run();  //这样调用不是使用新的线程。打印出来仍然是主线程。

        //通过thread触发
        Thread thread = new Thread(myThread);
        thread.start();

        Thread currentThread = Thread.currentThread();
        System.out.println("main Thread Name: " + currentThread.getName());
    }
}



package com.example.core.mydemo.thread;

/**
 * class Thread implements Runnable {
 * main线程名称=main
 * 线程运行Thread-0
 */
public class MyThread extends Thread{

    @Override
    public void run() {
        System.out.println("线程运行" + currentThread().getName());
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("main线程名称="+ currentThread().getName());
    }
}

 

posted on 2024-11-28 18:50  oktokeep  阅读(50)  评论(0)    收藏  举报