Java并发37:Executor系列--Executor接口学习笔记

1.Executor接口概述

@since 1.5

Executor,又称为执行器,它可以执行已经提交的Runnable接口类型的任务

这个接口提供了一种将任务提交任务运行(包括在线程使用、调度等待)分离出来的方法。

Executor接口通常用来显式地创建线程

例如,相较于为每一组任务调用new Thread(new(RunnableTask())).start(),你也可以使用下面的方式:

Executor executor = new Executor();
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
...

然而,Executor接口并不是严格的要求运行是异步的

在最简单的情况下,executor可以在调用者的线程中立即运行提交的任务:

class DirectExecutor implements Executor {
    public void execute(Runnable r) {
        r.run();
    }
}

更典型的是,任务运行在其他线程中,而非调用者的线程中。

下面的执行器为每一个任务开启一个新线程:

class ThreadPerTaskExecutor implements Executor {
    public void execute(Runnable r) {
        new Thread(r).start();
    }
}

很多Executor接口的实现类对如何以及何时调度任务施加了一些限制。

下面的执行器将任务提交给第二个执行器,构建了一个组合型的执行器

class SerialExecutor implements Executor {
    final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
    final Executor executor;
    Runnable active;

    SerialExecutor(Executor executor) {
        this.executor = executor;
    }

    public synchronized void execute(final Runnable r) {
        tasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    scheduleNext();
                }
            }
        });
        if (active == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
        if ((active = tasks.poll()) != null) {
            executor.execute(active);
        }
    }
}

ExecutorService接口是Executor接口的一种实现,是一种更加广泛的接口。

ThreadPoolExecutor类提供了一个可扩展的线程池的实现。

Executors工具类执行器提供了方便的工厂方法。


 

谨记一致性影响

一个线程中,提交一个Runnable类型的任务到执行器之前的操作 happens-before 另一个线程中,它运行之后的操作。
即:
一个线程中,提交一个Runnable类型的任务到执行器之前的操作 对 另一个线程中,它运行之后的操作 可见。


 

关于void execute(Runnable command)方法

作用:在将来的某个时刻,执行给定的命令。

基于执行器的实现方式的不同,命令执行的线程也会不同。
命令可能执行在一个新线程中、一个线程池管理的线程中或者一个调用者本身的线程中。

2.Executor的作用

Executor的主要作用:提供了一种显示创建线程的方式。

JDK1.5之前的方式:Thread + Runnable
Executor提供的的方式:Executor + Runnable

3.实例练习

练习目的:理解两种创建线程的方式。

练习内容

定义两个Runnable接口对象。
分别用Thread和Executor方式创建线程。
实例代码
//定义第1个Runnable接口对象Runnable runnable1 = new Runnable() {    @Override

public void run() {
        System.out.println(Thread.currentThread().getName() + " is first Runnable Object.");
    }
};
//定义第2个Runnable接口对象
Runnable runnable2 = new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is second Runnable Object.");
    }
};

System.out.println("======通过Thread运行:原始方式");
//方式1:通过Thread运行
Thread thread1 = new Thread(runnable1);
thread1.start();
Thread thread2 = new Thread(runnable2);
thread2.start();

Thread.sleep(100);
System.out.println();
System.out.println("======通过Executor运行:便于统一调度");
//方式2:通过Executor运行
//Executor通常通过Executors工具类的静态方法实例化对象
//这个地方用Executors创建线程不太好。请参考手动创建线程池,效果会更好哦。 
Executor executor = Executors.newCachedThreadPool(); //Executor只有一个方法execute(),用于执行Runnable接口 executor.execute(runnable1); executor.execute(runnable2);

运行结果:

======通过Thread运行:原始方式
Thread-1 is second Runnable Object.
Thread-0 is first Runnable Object.

======通过Executor运行:便于统一调度
pool-1-thread-1 is first Runnable Object.
pool-1-thread-2 is second Runnable Object.

 

posted @ 2021-09-02 19:59  姚春辉  阅读(122)  评论(0编辑  收藏  举报