Java并发——ScheduledExecutorService

ScheduledExecutorService

类 Scheduledexecutor Service的主要作用就是可以将定时任务与线程池功能结合使用。
在这里插入图片描述

ScheduledThreadPoolExecutor使用Callable延迟运行
public class MyCallableAA implements Callable<String> {
    @Override
    public String call() throws Exception {
        try {
            System.out.println("callA begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
            Thread.sleep(3000);
            System.out.println("callA end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "returnA";
    }
}



public class MyCallableBB implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("callB begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
        System.out.println("callB end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
        return "returnB";
    }
}


public class MyRun1 {
    public static void main(String[] args) {
        try {
            List<Callable> callables = new ArrayList<>();
            callables.add(new MyCallableAA());
            callables.add(new MyCallableBB());
            //调用方法newSingleThreadScheduledExecutor(),取得一个单任务的计划任务执行池
            ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
            ScheduledFuture<String> futureA = executorService.schedule(callables.get(0), 4L, TimeUnit.SECONDS);
            ScheduledFuture<String> futureB = executorService.schedule(callables.get(1), 4L, TimeUnit.SECONDS);

            System.out.println("     X=" + System.currentTimeMillis());
            System.out.println("返回值A:" + futureA.get());
            System.out.println("返回值B:" + futureB.get());
            System.out.println("     Y=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

从X到Y的运行时间为7秒,阻塞点是get()方法。
从运行结果中可以发现:public <V> Scheduled Future<V> schedule(Callable<v> callable, long delay, Time Unit unit)
方法中的第2个参数在多个任务中同时消耗时间,并不是一个任务执行完毕后再等待4秒继续执行的效果。由于第1个任务从计划任务到运行结束需要用时7秒,那么第2个任务其实是想在第4秒被执行,由于是单任务的计划任务池,所以第2个任务的执行时间被延后3秒。
在这里插入图片描述

在此实验中使用工厂类 Executors的 newSingleThreadScheduledExecutor方法来创建
ScheduledExecutorService对象,但返回的真正对象却是 Scheduledthreadpoolexecutor,因为
Scheduled Thread PoolExecutor实现了ScheduledexecutorService接口。
在这里插入图片描述

ScheduledThreadPoolExecutor使用Runnable延迟运行
public class MyRunnableAA implements Runnable {
    @Override
    public void run() {
        try {
            System.out.println("runnableA begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
            Thread.sleep(3000);
            System.out.println("runnableA end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class MyRunnableBB implements Runnable {
    @Override
    public void run() {
        System.out.println("runnableB begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
        System.out.println("runnableB end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
    }
}

public class MyRun2 {
    public static void main(String[] args) {
        List<Runnable> list = new ArrayList<>();
        list.add(new MyRunnableAA());
        list.add(new MyRunnableBB());
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

        System.out.println("     X=" + System.currentTimeMillis());
        executorService.schedule(list.get(0), 0L, TimeUnit.SECONDS);
        executorService.schedule(list.get(1), 1L, TimeUnit.SECONDS);
        System.out.println("     Y=" + System.currentTimeMillis());
    }
}

在这里插入图片描述

延迟运行并取得返回值
public class MyRun3 {
    public static void main(String[] args) {
        Callable<String> callable = new Callable<String>() {
            public String call() throws Exception {
                System.out.println("a call run =" + System.currentTimeMillis());
                return "returnA";
            }
        };

        try {
            List<Callable> list = new ArrayList<>();
            list.add(callable);
            ScheduledExecutorService exector = Executors.newSingleThreadScheduledExecutor();
            System.out.println("     X=" + System.currentTimeMillis());
            ScheduledFuture future = exector.schedule(list.get(0), 4L, TimeUnit.SECONDS);
            System.out.println(future.get() + "    A=" + System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

使用scheduleAtFixedRate()方法实现周期性执行
  • command:执行线程
  • initialDelay:初始化延时
  • period:两次开始执行最小间隔时间
  • unit:计时单位

执行任务时间大于>period预定的周期时间,也就是产生了超时的效果:

public class MyRun4 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("   begin=" + System.currentTimeMillis() +
                            " ThreadName=" + Thread.currentThread().getName());
                    Thread.sleep(4000);
                    System.out.println("   end=" + System.currentTimeMillis() +
                            " ThreadName=" + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        System.out.println("  X=" + System.currentTimeMillis());
        executor.scheduleAtFixedRate(runnable, 1, 2, TimeUnit.SECONDS);
        System.out.println("  Y=" + System.currentTimeMillis());
    }
}

任务执行时间(4)大于周期时间(2),所以产生超时效果,每次执行任务不再间隔2秒。
在这里插入图片描述

执行任务时间<period的时间:

public class MyRun5 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("  begin=" + System.currentTimeMillis() +
                        " ThreadName=" + Thread.currentThread().getName());
                System.out.println("  end=" + System.currentTimeMillis() +
                        " ThreadName=" + Thread.currentThread().getName());
            }
        };

        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        System.out.println("  X=" + System.currentTimeMillis());
        executor.scheduleAtFixedRate(runnable, 1, 2, TimeUnit.SECONDS);
        System.out.println("  Y=" + System.currentTimeMillis());
    }
}

每次间隔2秒执行。
在这里插入图片描述

注意: scheduleAtFixedRatel方法返回的 Scheduled
Future对象无法获得返回值,也就是scheduleAtFixedRate()方法不具有获得返回值的功能,而 schedule方法却可以获得返回值。所以当使用 scheduleAtFixedRate方法实现重复运行任务的效果时,需要结合自定义 Runnable接口的实现类,不要使用FutureTask类,因为FutureTask类并不能实现重复运行的效果。

使用scheduleWithFixedDelay()方法实现周期性执行

方法 schedule With FixedDelay(的主要作用是设置多个任务之间固定的运行时间间隔。

执行任务时间大于> period定的时间

public class MyRun6 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("  begin=" + System.currentTimeMillis() +
                            " ThreadName=" + Thread.currentThread().getName());
                    Thread.sleep(4000);
                    System.out.println("  end=" + System.currentTimeMillis() +
                            " ThreadName=" + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        System.out.println("  X=" + System.currentTimeMillis());
        executor.scheduleWithFixedDelay(runnable, 1, 2, TimeUnit.SECONDS);
        System.out.println("  Y=" + System.currentTimeMillis());
    }
}

固定每隔2秒执行一次。
在这里插入图片描述

执行任务时间<period:

public class MyRun6 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("  begin=" + System.currentTimeMillis() +
                        " ThreadName=" + Thread.currentThread().getName());
                System.out.println("  end=" + System.currentTimeMillis() +
                        " ThreadName=" + Thread.currentThread().getName());
            }
        };

        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        System.out.println("  X=" + System.currentTimeMillis());
        executor.scheduleWithFixedDelay(runnable, 1, 2, TimeUnit.SECONDS);
        System.out.println("  Y=" + System.currentTimeMillis());
    }
}

固定每隔2秒执行一次。
在这里插入图片描述

getQueue()与remove()方法

方法 getQueue()的作用是取得队列中的任务,而这些任务是未来将要运行的,正在运行的任务不在此队列中。使用 scheduleAtFixedRateO和 scheduleWithFixedDelay()两个方法实现周期性执行任务时,未来欲执行的任务都是放入此队列中。

public class MyRun7 {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);

        Runnable_A r1 = new Runnable_A("A");
        Runnable_A r2 = new Runnable_A("B");
        Runnable_A r3 = new Runnable_A("C");
        Runnable_A r4 = new Runnable_A("D");
        Runnable_A r5 = new Runnable_A("E");

        System.out.println(r1.hashCode());
        System.out.println(r2.hashCode());
        System.out.println(r3.hashCode());
        System.out.println(r4.hashCode());
        System.out.println(r5.hashCode());

        executor.scheduleAtFixedRate(r1, 10, 2, TimeUnit.SECONDS);
        executor.scheduleAtFixedRate(r2, 10, 2, TimeUnit.SECONDS);
        executor.scheduleAtFixedRate(r3, 10, 2, TimeUnit.SECONDS);
        executor.scheduleAtFixedRate(r4, 10, 2, TimeUnit.SECONDS);
        executor.scheduleAtFixedRate(r5, 10, 2, TimeUnit.SECONDS);

        System.out.println("");

        BlockingQueue<Runnable> queue = executor.getQueue();
        Iterator<Runnable> it = queue.iterator();
        while (it.hasNext()) {
            Runnable next = it.next();
            System.out.println("队列中的:" + next);
        }
    }
}

class Runnable_A implements Runnable {
    private String username;

    public Runnable_A(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    @Override
    public void run() {
        System.out.println("run! username=" + Thread.currentThread().getName());
    }
}

在这里插入图片描述

public class MyRun7 {
    public static void main(String[] args) throws InterruptedException {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);

        Runnable_A r1 = new Runnable_A("A");
        Runnable_A r2 = new Runnable_A("B");

        ScheduledFuture<?> future1 = executor.scheduleAtFixedRate(r1, 0, 2, TimeUnit.SECONDS);
        Thread.sleep(1000);
        ScheduledFuture<?> future2 = executor.scheduleAtFixedRate(r2, 10, 2, TimeUnit.SECONDS);
        Thread.sleep(5000);
        System.out.println(executor.remove((Runnable) future2));
        System.out.println("");

        BlockingQueue<Runnable> queue = executor.getQueue();
        Iterator<Runnable> it = queue.iterator();
        while (it.hasNext()) {
            Runnable next = it.next();
            System.out.println("队列中的:" + next);
        }
    }
}

class Runnable_A implements Runnable {
    private String username;

    public Runnable_A(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    @Override
    public void run() {
        System.out.println("run! username=" + Thread.currentThread().getName());
    }
}

在这里插入图片描述

setExecuteExistingDelayedTasksAfterShtudownPolicy()

方法 setExecuteExisting DelayedTasksAfterShutdownPolicy()的作用是当对 ScheduledThreadPoolExecutor执行了shutdown方法时,任务是否继续运行,默认值是true,也就是
当调用了 shutdown方法时任务还是继续运行,当使用 set ExecuteExistingDelayedTasksAfterShutdownPolicy(alse)时任务不再运行。

public class MyRun8 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    System.out.println("任务执行!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
        executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
        executor.schedule(runnable, 3, TimeUnit.SECONDS);
        executor.shutdown();
        System.out.println("main end");
    }
}

在这里插入图片描述

注意:方法setExecuteExistingDelayedTasksAfterShutdownPolicy可以与 schedule()和 shutdown()方法联合使用,但 setExecuteExistingDelayedTasksAfterShutdownPolicy()方法不能与 scheduleatFixedRate()和 scheduleWithFixedDelay()方法联合使用。

那么如果想实现 shutdown关闭线程池后,池中的任务还会继续重复运行,则要将 scheduleatFixedRate和 scheduleWithFixedDelayo方法与 setContinueExistingPeriodicTasksAfterShutdownPolicy()方法联合使用。

setContinueExistingPeriodicTasksAfterShutdownPolicy()

方法 setContinueExistingPeriodicTasksAfterShutdownPolicy()传入tue的作用是当使用 scheduleAtFixedRate()方法或 scheduleWithFixedDelay()方法时,如果调用 ScheduledThreadPoolExecutor对象的 shutdown()方法,任务还会继续运行,传入false时任务不运行,进程销毁。

public class MyRun8 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    System.out.println("任务执行!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
        executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
        executor.scheduleWithFixedDelay(runnable, 0,3, TimeUnit.SECONDS);
        executor.shutdown();
        System.out.println("main end");
    }
}

在这里插入图片描述

cancel(boolean)与setRemoveOnCancelPolicy()
  • 方法 cancel(boolean)的作用设定是否取消任务。
  • 方法 setRemove On CancelPolicy (boolean)的作用设定是否将取消后的任务从队列中清除。
public class MyRun9 {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
        Runnable runnable1 = new Runnable_B("A");
        ScheduledFuture<?> future = executor.schedule(runnable1, 1, TimeUnit.SECONDS);
        System.out.println(future.cancel(true));
        System.out.println("");
        BlockingQueue<Runnable> queue = executor.getQueue();
        Iterator<Runnable> it = queue.iterator();
        while (it.hasNext()) {
            Runnable next = it.next();
            System.out.println("队列中的:" + next);
        }
        System.out.println("main end");
    }
}

class Runnable_B implements Runnable {

    private String username;

    public Runnable_B(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public void run() {
        try {
            while (true) {
                if (Thread.currentThread().isInterrupted() == true) {
                    throw new InterruptedException();
                }
                System.out.println("run! username=" + username + " " + Thread.currentThread().getName());
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("中断了!");
        }
    }
}

删除成功,但是还保留在队列中。
在这里插入图片描述

在这里插入图片描述
删除成功,从队列中剔除。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值