4.线程池详解

目录

线程池

1.为什么使用线程池(优势)

2.线程池底层原理

3.几种线程池如何工作的?

4.几种线程池的使用Demo

5.使用线程池好处

 

线程池

1.为什么使用线程池(优势)

  • 我们使用线程的时候就去创建一个线程,这样实现起来非常简单,
  • 但是就会出现一个问题:如果并发的线程数量很多,并且每一个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
  • 有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是继续执行其它任务,在java中可以通过线程池来表达这样的效果。

2.线程池底层原理

  • 线程池可以理解为容器(集合),一般使用集合(ArrayList,HashSet,LinkedList,HashMap)来充当容器,
  • 常用LinkedList<Thread>集合作为容器,泛型就是线程即集合中存放的都是线程。下面是在LinkedList集合中通过add方法向集合中添加一些线程即add(new Thread(xxx))。
  • 1.当程序第一次启动时,创建多个线程,保存到一个集合中。
  • 2.当我们想要使用线程的时候,就可以从集合中取出线程使用。
    •  Thread t=list.remove(0):从List集合中移除第0个线程(线程只能被一个任务使用)
    • Thread t=linked.removeFirst():从LikedList集合中移除第1个线程
  • 3.当我们使用完线程,需要将线程归还给线程池:即将线程再添加到集合中,(这里面有队列机制,从对头取出,队尾归还)
    • 若是List集合,则list.add(t);将线程归还到list集合末尾
    • 若是LinkedList集合,则linked.addLast(t);将线程归还到LinkedList集合尾端。

注意:

  • JDK1.5之后,JDK内置了线程池,我们可以直接使用。

3.几种线程池如何工作的?

任务加入后各个线程池执行流程:

缓存线程池

  • 1.判断线程池是否存在空闲线程,存在则使用,不存在则创建线程放入线程池再使用。
  • 2.长度无限制。

定长线程池

  • 判断线程池是否存在空闲线程,存在则使用
  • 不存在空闲线程,且线程池未满,则创建线程放入线程池,再使用。
  • 不存在空闲线程,且线程池已满,则等待出现空闲线程再使用
  • 线程池线程长度是指定的数值。

单线程线程池

  • 判断线程池的那个线程是否空闲,空闲则使用,不空闲则等待这个线程空闲再用。
  • 池中只有一个线程,相当于获取定长线程池传参1效果。

周期定长线程池

  • 判断线程池是否存在空闲线程,存在则使用。
  • 不存在空闲线程,且线程池未满,则创建线程放入线程池,然后使用。
  • 不存在空闲线程,且线程池已满,则等待线程池存在空闲线程。
  • 实现定时执行或定时周期执行任务,当某个时机触发时,自动执行某个任务。

4.几种线程池的使用Demo

线程池:JDK1.5之后提供的

  • 1.java.util.concurrent.Executors:线程池工厂类,用来创建线程池
  • 2.Executors类中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads){}
创建一个可重用 固定线程数的线程池
参数:int nThreads:创建线程池中包含的线程数量
返回值:返回的是ExecutorService接口的实现类对象,可以使用该接口接收(面向接口编程)
  • 3.java.util.concurrent.ExecutorService:线程池接口
    • 用来从线程池中获取线程,调用start方法,执行线程任务
    • submit(Runnable task)提交一个Runnable任务用于执行
    • 关闭/销毁线程池的方法void shutdowm()

 * 4.线程池的使用步骤:

  • 1.使用线程池的工厂类Executors里面提供的静态方法newFixedThreadPool创建一个指定线程数量的线程池,并用ExecutorService接口接收。
  •  2.创建一个类,实现Runnable接口,重写run方法,设置线程任务
  •  3.调用ExecutorService中方法submit,传递线程任务(实现类),开启线程,执行run方法
  • 4.调用ExecutorService中的方法shutdown销毁销毁线程池(不建议)
package Thread.demo17.ThreadPool;
/**
 * 2.创建一个类,实现Runnable接口,重写run方法,设置线程任务
 */
public class RunnableImpI implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"创建一个新的" +"线程执行");
    }
}


package Thread.demo17.ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo1ThreadPool {
    public static void main(String[] args) {
        //1.使用线程池的工厂类Executors里面提供的静态方法newFixedThreadPool
        //  创建一个指定线程数量的线程池,并用ExecutorService接口接收。
        ExecutorService es= Executors.newFixedThreadPool(2);//两个线程
        //3.线程池调用ExecutorService中submit,传递线程任务(实现类),开启线程,执行run方法
        //传递三个线程任务,这三个线程任务相同,也可以创建多个实现类(线程任务)
        es.submit(new RunnableImpI());//pool-1-thread-2创建一个新的线程执行
        es.submit(new RunnableImpI());//pool-1-thread-1创建一个新的线程执行
        //线程池会一直开启,使用完了线程,会自动把线程归还线程池,线程可以继续使用
        es.submit(new RunnableImpI());//pool-1-thread-1创建一个新的线程执行
        //4.调用ExecutorService中的方法shutdown销毁销毁线程池(不建议)
        es.shutdown();
    }
}

CachedThreadPool

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

/**
 * 缓存线程池的使用
 * 1.判断线程池是否存在空闲线程,存在则使用,不存在则创建线程放入线程池再使用。
 * 2.长度无限制。
 */
public class CachedThreadPool {
    public static void main(String[] args) {
        //获取缓存线程池
        ExecutorService service = Executors.newCachedThreadPool();
        //指挥线程池执行线程任务(线程任务使用匿名内部类写法)
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":"+"你好啊");
            }
        });

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":"+"我很好");
            }
        });

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":"+"我也很好");
            }
        });

        try {
            Thread.sleep(5000);
            System.out.println("休眠5s");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":"+"我还好");
            }
        });
    }
}

FixedThreadPool

package demo24threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * 定长线程池:即指定线程池线程数量
 * 判断线程池是否存在空闲线程,存在则使用
 * 不存在空闲线程,且线程池未满,则创建线程放入线程池,再使用。
 * 不存在空闲线程,且线程池已满,则等待出现空闲线程再使用
 * 线程池线程长度是指定的数值。
 */
public class FixedThreadPool {
    public static void main(String[] args) {
        //获取定长线程池,设置池中线程数为2
        ExecutorService service = Executors.newFixedThreadPool(2);
        //线程池分配线程执行线程任务(任务使用匿名内部类)
        service.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程1开始执行任务1,此处休眠3s,线程1一直被占用");
                    Thread.sleep(3000);
                    System.out.println("休眠结束,线程1继续执行线程任务");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+":"+"任务1:你好啊");
            }
        });

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":"+"任务2:我很好");
            }
        });

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":"+"任务3:我也很好");
            }
        });
    }
}

SingleThreadPool

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

/**
 * 单线程线程池:
 * 判断线程池的那个线程是否空闲,空闲则使用,不空闲则等待这个线程空闲再用。
 * 池中只有一个线程,相当于获取定长线程池传参1效果
 */
public class SingleThreadPool {
    public static void main(String[] args) {
        //获取单线程线程池
        ExecutorService service = Executors.newSingleThreadExecutor();
        //线程池分配线程执行线程任务
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":"+"你好啊");
            }
        });

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":"+"我很好");
            }
        });

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":"+"我也很好");
            }
        });
    }
}

ScheduledThreadPool

package demo24threadpool;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 周期定长线程池
 *
 * 判断线程池是否存在空闲线程,存在则使用。
 * 不存在空闲线程,且线程池未满,则创建线程放入线程池,然后使用。
 * 不存在空闲线程,且线程池已满,则等待线程池存在空闲线程。
 * 实现定时执行或定时周期执行任务,当某个时机触发时,自动执行某个任务。
 */
public class ScheduledThreadPool {
    public static void main(String[] args) {
        //获取周期定长线程池,设置池中线程数为2
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);

        //线程池分配线程执行线程任务

        //1.定时执行一次,定时3s后执行
        //参数1:为要定时执行的任务
        //参数2:设置定时时长
        //参数3:设置时长单位,使用TimeUnit工具类中常量指定
        service.schedule(new Runnable(){
            @Override
            public void run() {
                System.out.println("定时3s后线程执行线程任务");
                System.out.println(Thread.currentThread().getName() + ";你好啊");
            }
        }, 3, TimeUnit.SECONDS);

        //2.周期执行任务,5s后每隔1s执行一次任务
        //参数1:线程任务
        //参数2:延迟时长(即第一次执行在什么时间以后)
        //参数3:周期时长(每隔多久执行一次)
        //参数4:时长单位,使用TimeUnit工具类
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("5s后每隔1s执行一次线程任务");
                System.out.println(Thread.currentThread().getName() + ";你好啊");
            }
        },5,1,TimeUnit.SECONDS);
    }
}

5.使用线程池好处

  • 1.降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  • 2.提高响应速度。当任务到达时,任务不需要等到线程创建就能立即执行。
  • 3.提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,而把服务器搞垮(每个线程需要大约1MB,线程开的越多,消耗的内存也就越大)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值