线程和线程池 基础

一、线程的使用

1)重写Thread的run()函数

 class MyThread extends Thread {
    public int index = 0;

    MyThread(int index) {
        this.index = index;
    }

    @Override
    public void run() {
        System.out.println(index);
    }
}
public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        for (int i = 0; i < 20; i++) {
            new MyThread(i).start();
        }
    }
}

2)实现Runnable接口

class Mytask implements Runnable {
    private int index = 0;

    public Mytask(int index) {
        this.index = index;
    }

    public void run() {
        System.out.println(index);
    }
}
public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        for (int i = 0; i < 20; i++) {
            new Thread(new Mytask(i)).start();
        }
    }
}

3)有返回值的线程

  • Callable和FutureTask 获取线程返回值
  • futureTask.get()会阻塞调用者线程,直到子线程有反回值。
class CallbleTask implements Callable<Integer> {

    public Integer call() throws Exception {
        Thread.sleep(1000);
        return 100;
    }
}
public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallbleTask callbleTask = new CallbleTask();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callbleTask);
        new Thread(futureTask).start();

        System.out.println(futureTask.get());
    }
}

二、线程池

1、ThreadPoolExecutor线程池

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

- corePoolSize:核心线程池数量

  • 线程池中可以长时间存活的最大线程数量,即这些线程创建后不会被销毁
  • 在线程数少于核心数量时,有新任务进来优先考虑就新建一个线程执行任务。
  • 如果新任务进来时,当前所有核心线程都繁忙,则将任务放到工作队列排队(工作队列未满的情况下)。
  • 核心线程执行完一个任务后,将检查工作队列是否有等待执行的任务,有任务则取出一个任务执行,反之,则保持空闲状态。

- maximumPoolSize:最大线程数量

  • 线程池中包含的最大线程数量,包括核心线程 。
  • 如果任务队列满了,并且池中线程数小于最大线程数,会再创建新的线程执行任务。
  • 核心线程之外的线程在空闲一段时间后会被销毁,减少占用资源。

- keepAliveTime:核心线程外的线程存活时间,即线程空闲时的存活时间

- workQueue:保存等待执行任务的阻塞队列

  当线程池中的核心线程都在执行任务时,再次到来的任务将保存到工作队列中。
  • 1)SynchronousQueue(同步队列):该队列不保存任务,作为任务中转站使用,任务进入队列后马上进行提交;如果没有空闲线程,则尝试创建新的线程,如果线程数量达到最大值,则使用拒绝策略;
  • 2)ArrayBlockingQueue(有界阻塞队列):如果线程数量小于corePoolSize时,会优先创建新线程,若大于corePoolSize,则会将新任务加入到等待队列;等待队列已满,则在总线程数不大于maxinumPoolSize的前提下,创建新的线程执行任务,若大于,则执行拒绝策略;
  • 3)LinkedBlockQueue(无界阻塞队列):除非系统资源耗尽,否则无界的任务队列不存在任务入队列失败的情况;新任务到来时,如果线程数小于corePoolSize, 则创建新的线程执行任务,但当线程池中线程达到poolSize后,就不会增加;
  • 4)PriorityBlockingQueue(优先级队列):可以控制任务执行的先后顺序,它是一个特殊的无界队列。

- threadFactory:创建线性的工厂类

- handler:任务拒绝策略;新任务到来,但是线程池已达到最大线程数,且没有线程空闲,有四种策略

  • ThreadPoolExecutor.AbortPolicy:直接抛出 RejectedExecutionException 异常,本策略也是默认的饱和策略。

  • ThreadPoolExecutor.CallerRunsPolicy:使用调用者所在线程来运行任务。

  • ThreadPoolExecutor.DiscardPolicy:忽略新来的任务,什么也不做。

  • ThreadPoolExecutor.DiscardOldestPolicy:把队列中等待时间最久的任务丢弃,然后把新任务保存到队列中。

2、Executors工厂类创建线程池(四种常用线程池)

1)newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
  • 底层是ThreadPoolExecutor。
  • 核心线程数和最大线程数相等。
  • 不存在非核心线程,所以存活时间和时间单元不起作用。
  • 使用无界阻塞队列LinkedBlockingQueue保存待执行任务,容量默认容量 Integer.MAX_VALUE。

2)newSingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
  • 底层是ThreadPoolExecutor,但是有封装了一层,线程池一经创建就不能够更改 (比如向上转型)
  • 核心线程和最大线程数相等,且等于1,所有任务串行执行。
  • 无界阻塞队列。

3)newCachedThreadPool

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
  • 核心线程为0,最大线程为Integer.MAX_VALUE。
  • 所有线程的空闲存活时间为60s。
  • 使用同步队列传递任务,该队列不保存任务
  • 新任务到来,直接放到SynchronousQueue中,有空闲线程则直接取出任务执行,没有空闲线程则新建线程执行任务(SynchronousQueue作为新任务过渡的场所)。

4)newScheduledThreadPool

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}


public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}
  • 底层是ScheduledThreadPoolExecutor,继承ThreadPoolExecutor类,并实现
    ScheduledExecutorService接口。
  • 核心线程数量由corePoolSize决定,最大线程数为Integer.MAX_VALUE。
  • 核心线程之外的线程存活时间为0,线程执行任务结束就被销毁。

3、线程池使用

1)ThreadPoolExecutor

public static void main(String[] args) {
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 60, 10000, TimeUnit.SECONDS,
     new LinkedBlockingQueue<Runnable>(15));

    for (int i = 0; i < 50; i++) {
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());


                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


            }
        });
    }

}

指定阻塞队列大小,执行结果
在这里插入图片描述
注:

  1. 核心线程为3,最大线程数为60,阻塞队列大小为15。
  2. 阻塞队列满了之后,才会创建非核心线程。
  3. thread_1、thread_2和thread_3是核心线程。
  4. 下面不指定阻塞队列大小,默认队列不会满,所以只使用核心线程执行任务:
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 60, 10000, TimeUnit.SECONDS,
 new LinkedBlockingQueue<Runnable>());

在这里插入图片描述

2)newFixedThreadPool

  • 含两个固定线程的线程池
public static void main(String[] args) {
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
    for (int i = 0; i < 20; i++) {
        fixedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
    }

}

在这里插入图片描述
3)newSingleThreadExecutor

  • 但线程的线程池,串行执行任务
public static void main(String[] args) {
    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 20; i++) {
        singleThreadExecutor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
    }

4)newCachedThreadPool

  • 任务不会被阻塞到等待队列中,所有任务均会快速获取线程执行。
  • 有空闲线程,则直接从队列取出任务执行。
  • 没有空闲线程,则立即创建线程
public static void main(String[] args) {
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    for (int i = 0; i < 50; i++) {
        cachedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
    }
}

4) newScheduledThreadPool

  • 提交任务后,延迟5s后执行。
public static void main(String[] args) {
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
    for (int i = 0; i < 50; i++) {
        scheduledThreadPool.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());

            }
        },10,TimeUnit.SECONDS);
    }

}
  • 延时3s后开始执行任务,然后每个10s定时执行
public static void main(String[] args) {

    final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
    System.out.println("提交任务:  " + df.format(new Date()));
    scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            System.out.println("执行任务: " + df.format(new Date()));
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, 3, 10, TimeUnit.SECONDS);

}

在这里插入图片描述

  • 延时3s后开始执行任务;然后,上一个任务执行完成后,延迟10s执行下一次定时任务
public static void main(String[] args) {

    final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
    System.out.println("提交任务:  " + df.format(new Date()));
    scheduledThreadPool.scheduleWithFixedDelay  (new Runnable() {
        @Override
        public void run() {
            System.out.println("执行任务: " + df.format(new Date()));
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, 3, 10, TimeUnit.SECONDS);

}

在这里插入图片描述

注:两个定时任务,scheduleWithFixedDelay  以上一次任务执行结束后开始计时(相邻任务执行时间间隔=上一次任务执行时间+给定的时间间隔);
scheduleAtFixedRate以上一次任务开始执行时计时(相邻任务执行时间间隔=给定的时间间隔)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值