线程及线程池详解(参数及代码一文搞懂)

提示:动态每日更新算法题,想要一起学习的小伙伴可以关注一下


一、线程详解

 每个进程都有自己的地址空间,即进程空间。一个服务器通常需要接收大量并发请求,为每一个请求都创建一个进程系统开销大、请求响应效率低,因此操作系统引进线程。

1. 线程的特点

  • 进程中的一个实体
  • 进程的一个执行路径
  • CPU 调度和分派的基本单位
  • 线程本身是不会独立存在
  • 当前线程 CPU 时间片用完后,会让出 CPU 等下次轮到自己时候在执行
  • 系统不会为线程分配内存,线程组之间只能共享所属进程的资源,线程只拥有在运行中必不可少的资源(如程序计数器、栈)
  • 线程里的程序计数器就是为了记录该线程让出 CPU 时候的执行地址,待再次分配到时间片时候就可以从自己私有的计数器指定地址继续执行

 下面实现线程的四个方法 1和2不能控制资源且没有返回值,方法3可以有返回值且可以处理异常,方法4在高并发情况下可以使用,合理控制资源不会造成资源耗尽。

2.实现线程的4个方法

  • 继承Thread
  • 实现Runnable接口
  • 实现Callable接口+FutureTask
  • 线程池

2.1 继承Thread类

public class ThreadTest02 {
	public static void main(String[] args) {
		Processor p = new Processor();
		/*
			采用 start 启动线程,不是直接调用 run,
			start 不是马上执行线程,而是使线程进入就绪状态
			线程的真正执行是由 Java 的线程调度机制完成的。
		*/
		p.start();
	}
}
class Processor extends Thread {
	public void run() {
		for (int i=0; i<10; i++) {
			System.out.println(i);
		}
	}
}

2.2 实现Runnable接口

public class test extends Thread{
    public static void main(String[] args) {
        MyThread thread1=new MyThread("test1");
        MyThread thread2=new MyThread("test2");
        MyThread thread3=new MyThread("test3");

        new Thread(thread1).start();
        new Thread(thread2).start();
        new Thread(thread3).start();
    }

}


class MyThread implements Runnable{
    private String name;
    public MyThread(String name){
        this.name=name;
    }
    @Override
    public void run(){
        for(int i=0;i<200;i++){
            System.out.println(this.name+"--->"+i);
        }
    }
}


2.3 实现Callable接口+FutureTask

 特地说一下此方法可以拿到返回值且可以处理异常

public class CallableTest {
    public static void main(String[] args) throws Exception,  {
        MyThread myThread = new MyThread();
        FutureTask<String> futureTask = new FutureTask(myThread);
        new Thread(futureTask, "A").start();
        String result = (String) futureTask.get();//拿到返回结果
        log.info("result:{}", result);
    }
}

class MyThread implements Callable<String> {

    @Override
    public String call() throws Exception {
        log.info("test callable()");
        TimeUnit.SECONDS.sleep(5);
        return "callable";
    }
}

2.4 线程池

public static void fixedThreadPool() {
    // 创建 2 个数据级的线程池
    ExecutorService threadPool = Executors.newFixedThreadPool(2);

    // 创建任务
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
        }
    };

    // 线程池执行任务(一次添加 4 个任务)
    // 执行任务的方法有两种:submit 和 execute
    threadPool.submit(runnable);  // 执行方式 1:submit
    threadPool.execute(runnable); // 执行方式 2:execute
    threadPool.execute(runnable);
    threadPool.execute(runnable);
}

二、线程池详解

1.七大参数详解

public ThreadPoolExecutor(
  int corePoolSize,//线程池中的常驻核心线程数
  int maximumPoolSize,//线程池能够容纳同时执行的最大线程数,此值必须大于等于1
  long keepAliveTime,//多余的空闲线程的存活时间。
  TimeUnit unit,//keepAliveTime的单位
  BlockingQueue<Runnable> workQueue,//任务队列,被提交但尚未被执行的任务。
  ThreadFactory threadFactory,//生成线程池中工作线程的线程工厂,用于创建线程一般用默认的
  RejectedExecutionHandler handler)//拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数
    }

2. 线程池创建线程流程

在这里插入图片描述

  1. 当线程数小于核心线程数时,创建线程。
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  3. 当线程数大于等于核心线程数,且任务队列已满有两种选择:
     若线程数小于最大线程数,创建线程;
     若线程数等于最大线程数,抛出异常,拒绝任务。

3.七大不同线程池创建

 线程池的创建方式总共包含7 种(其中 6 种是通过 Executors 创建的,1 种是通过 ThreadPoolExecutor创建的)
不同的

3.1 FixedThreadPool

创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待。

public static void fixedThreadPool() {
    // 创建 2 个数据级的线程池
    ExecutorService threadPool = Executors.newFixedThreadPool(2);

    // 创建任务
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
        }
    };

    // 线程池执行任务(一次添加 4 个任务)
    // 执行任务的方法有两种:submit 和 execute
    threadPool.submit(runnable);  // 执行方式 1:submit
    threadPool.execute(runnable); // 执行方式 2:execute
    threadPool.execute(runnable);
    threadPool.execute(runnable);
}

3.2 CachedThreadPool

 创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程。

public static void cachedThreadPool() {
    // 创建线程池
    ExecutorService threadPool = Executors.newCachedThreadPool();
    // 执行任务
    for (int i = 0; i < 10; i++) {
        threadPool.execute(() -> {
            System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
        });
    }
}

3.3 SingleThreadExecutor

 创建单个线程数的线程池,它可以保证先进先出的执行顺序。

public static void singleThreadExecutor() {
    // 创建线程池
    ExecutorService threadPool = Executors.newSingleThreadExecutor();
    // 执行任务
    for (int i = 0; i < 10; i++) {
        final int index = i;
        threadPool.execute(() -> {
            System.out.println(index + ":任务被执行");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
        });
    }
}

3.4 ScheduledThreadPool

创建一个可以执行延迟任务的线程池。

public static void scheduledThreadPool() {
    // 创建线程池
    ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);
    // 添加定时执行任务(1s 后执行)
    System.out.println("添加任务,时间:" + new Date());
    threadPool.schedule(() -> {
        System.out.println("任务被执行,时间:" + new Date());
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
        }
    }, 1, TimeUnit.SECONDS);
}

3.5 SingleThreadScheduledExecutor

创建一个单线程的可以执行延迟任务的线程池。

public static void SingleThreadScheduledExecutor() {
    // 创建线程池
    ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
    // 添加定时执行任务(2s 后执行)
    System.out.println("添加任务,时间:" + new Date());
    threadPool.schedule(() -> {
        System.out.println("任务被执行,时间:" + new Date());
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
        }
    }, 2, TimeUnit.SECONDS);
}

3.6 newWorkStealingPool

创建一个抢占式执行的线程池(任务执行顺序不确定)

public static void workStealingPool() {
    // 创建线程池
    ExecutorService threadPool = Executors.newWorkStealingPool();
    // 执行任务
    for (int i = 0; i < 10; i++) {
        final int index = i;
        threadPool.execute(() -> {
            System.out.println(index + " 被执行,线程名:" + Thread.currentThread().getName());
        });
    }
    // 确保任务执行完成
    while (!threadPool.isTerminated()) {
    }
}

3.7 ThreadPoolExecutor

最原始的创建线程池的方式

public static void myThreadPoolExecutor() {
    // 创建线程池
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));
    // 执行任务
    for (int i = 0; i < 10; i++) {
        final int index = i;
        threadPool.execute(() -> {
            System.out.println(index + " 被执行,线程名:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值