Java线程池和定时线程池

1.线程使用

1.继承Thread类,重写run()方法,创建对象后使用start()方法(不推荐)
2.实现Runnable接口
3.实现Callable接口,相比Runnable多了异步执行的返回值
4.使用lambda实现,简单常用,但不算一种新方式

public class ThreadMainTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    	// Thread
        new ThreadTest().start();
        // Runnable
        new Thread(new RunnableTest()).start();
		// Callable
        FutureTask<String> threadTask= new FutureTask<>(new CallableTest("带返回值的"));
        new Thread(threadTask).start();
        System.out.println(threadTask.get());
		// 4.lambda
        new Thread(()->{
            System.out.println("lambda:" + Thread.currentThread().getName());
        }).start();
    }
}
class ThreadTest extends Thread{
    @Override
    public void run() {
        System.out.println("Thread:" + Thread.currentThread().getName());
        super.run();
    }
}

class RunnableTest implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable:" + Thread.currentThread().getName());
    }
}

class CallableTest implements Callable<String> {

    private String name;
    public CallableTest(String name) {
        this.name = name;
    }
    @Override
    public String call() throws Exception {
        System.out.println("Callable:" + Thread.currentThread().getName());
        return name;
    }
}

2.线程池介绍

使用ThreadPoolExecutor构建线程池,不建议使用Executors创建线程

2.1ThreadPoolExecutor参见介绍

2.1.1 corePoolSize 核心线程数

1.corePoolSize 核心线程数:该线程池内的常驻线程

2.1.2 maximumPoolSize 最大线程:

2.maximumPoolSize 最大线程:
当添加一个任务时,corePoolSize 已满,线程池还没达到maximumPoolSize,并且没有空闲线程,workQueue已满的情况下,创建一个新线程并执行。

2.1.3 keepAliveTime

3.keepAliveTime 线程回收策略:当池内的线程数大于corePoolSize并且空闲时长达到keepAliveTime 时,执行回收策略

2.1.4 unit

4.unit描述keepAliveTime的单位

2.1.5 workQueue工作队列

5.workQueue工作队列
存放待执行任务的队列:当提交的任务数超过corePoolSize 大小后,再提交的任务就存放在workQueue,任务调度时再从队列中取出任务。它仅仅用来存放被execute()方法提交的Runnable任务。workQueue实现了BlockingQueue接口。
JDK默认的工作队列有五种:
ArrayBlockingQueue 数组型阻塞队列:数组结构,初始化时传入大小,有界,FIFO,使用一个重入锁,默认使用非公平锁,入队和出队共用一个锁,互斥。
LinkedBlockingQueue 链表型阻塞队列:链表结构,默认初始化大小为Integer.MAX_VALUE,有界(近似无界),FIFO,使用两个重入锁分别控制元素的入队和出队,用Condition进行线程间的唤醒和等待。
SynchronousQueue 同步队列:容量为0,添加任务必须等待取出任务,这个队列相当于通道,不存储元素。
PriorityBlockingQueue 优先阻塞队列:无界,默认采用元素自然顺序升序排列。
DelayQueue 延时队列:无界,元素有过期时间,过期的元素才能被取出。

2.1.6 threadFactory线程工厂

6.threadFactory线程工厂
创建线程的工厂,可以设定线程名、线程编号等。
DefaultThreadFactory(默认工厂)

2.1.7 rejectedExecutionHandler 拒绝策略

7.rejectedExecutionHandler拒绝策略
当线程池线程数已满,并且工作队列达到限制,新提交的任务使用拒绝策略处理。可以自定义拒绝策略,拒绝策略需要实现RejectedExecutionHandler接口。
JDK默认的拒绝策略有四种:
AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。(默认策略)
DiscardPolicy:丢弃任务,但是不抛出异常。可能导致无法发现系统的异常状态。
DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。
CallerRunsPolicy:由调用线程处理该任务。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5, // corePoolSize 
    10, // maximumPoolSize
    60, // keepAliveTime
    TimeUnit.SECONDS, // unit
    new LinkedBlockingQueue<>(), // workQueue
    threadFactory, //线程工厂
    rejectedExecutionHandler //拒绝策略
);

3.定时线程池ScheduledExecutorService

/**
 * 带延迟时间的调度,延迟unit单位delay,只执行一次
 * 调度之后可通过Future.get()阻塞直至任务执行完毕
 */
1. public ScheduledFuture<?> schedule(Runnable command,
                                      long delay, TimeUnit unit);

/**
 * 带延迟时间的调度,只执行一次
 * 调度之后可通过Future.get()阻塞直至任务执行完毕,并且可以获取执行结果
 */
2. public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                          long delay, TimeUnit unit);

/**
 * 带延迟时间的调度,循环执行,固定频率
 */
3. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                 long initialDelay,
                                                 long period,
                                                 TimeUnit unit);

/**
 * 带延迟时间的调度,循环执行,固定延迟
 */
4. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                    long initialDelay,
                                                    long delay,
                                                    TimeUnit unit);

方法1:schedule(Runnable command, long delay, TimeUnit unit)

    @Test
    public void test_schedule4Runnable() throws Exception {
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        ScheduledFuture future = service.schedule(() -> {
            try {
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("task finish time: " + format(System.currentTimeMillis()));
        }, 1000, TimeUnit.MILLISECONDS);
        System.out.println("schedule finish time: " + format(System.currentTimeMillis()));

        System.out.println("Runnable future's result is: " + future.get() +
                ", and time is: " + format(System.currentTimeMillis()));
    }

方法2:schedule(Callable<V> callable, long delay, TimeUnit unit)

这里代码不再赘述,在schedule方法最后加入return返回即可。和Runnable基本相同,唯一的区别在于future.get()能拿到Callable返回的真实结果。

@Test 
public void schedule4CallableTest() throws Exception {
    ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
    ScheduledFuture<String> future = service.schedule(() -> {
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task finish time: " + format(System.currentTimeMillis()));
        return "success";
    }, 1000, TimeUnit.MILLISECONDS);
    System.out.println("schedule finish time: " + format(System.currentTimeMillis()));

    System.out.println("Callable future's result is: " + future.get() +
            ", and time is: " + format(System.currentTimeMillis()));
}

方法3:scheduleAtFixedRate(Runnable command,long initialDelay, long period,TimeUnit unit);

固定频率地对一个任务循环执行,任务初始延迟initialDelay,任务执行间隔为period,单位是unit

@Test 
public void scheduleAtFixedRateTest() {
    ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
    service.scheduleAtFixedRate(() -> {
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task finish time: " + format(System.currentTimeMillis()));
    }, 1000L, 1000L, TimeUnit.MILLISECONDS);

    System.out.println("schedule finish time: " + format(System.currentTimeMillis()));
    while (true) { }
}

方法4:scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);

固定延迟地对一个任务循环执行,任务初始延迟initialDelay,任务执行间隔为period。单位是unit

@Test 
public void scheduleWithFixedDelayTest() {
    ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
    service.scheduleWithFixedDelay(() -> {
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task finish time: " + format(System.currentTimeMillis()));
    }, 1000L, 1000L, TimeUnit.MILLISECONDS);

    System.out.println("schedule finish time: " + format(System.currentTimeMillis()));
    while (true) { }
}

固定频率scheduleAtFixedRate()固定延迟scheduleWithFixedDelay()的区别`
scheduleAtFixedRate()为固定频率,scheduleWithFixedDelay()为固定延迟。固定频率是相对于任务执行的开始时间,而固定延迟是相对于任务执行的结束时间。比如有个任务执行时间特别长,如果使用固定频率,可能会导致当前任务没执行完就开始新的周期任务。这种情况比较适合固定延迟

  • 39
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值