1.并发工具类是什么
一组用于克服java底层线程问题的类和接口的框架
特别地,低级的并发原语如synchronized和wait()/notify()经常难以正确使用
过于依赖这些并发原语会导致性能问题,从而影响了应用程序的扩展性
java底层的线程功能也并未包含线程池以及信号量这样的高级构造

2.指出并发工具类型位于哪些包下面
java.util.concurrent、java.util.concurrent.atomic、java.util.concurrent.locks

3.给出任务的定义
它的类实现了java.lang.Runnable(一个可运行的任务)或者java.util.concurrent.Callable接口(一个可被调用的任务)

4.给出executor的定义
它的类直接或间接地实现了java.util.concurrent.Executor接口,这样便从任务执行机制中解耦任务的提交操作

5.说明Executor接口的局限性
Executor接口仅仅只关注Runnable接口
也就是说,一个可运行任务是没法简单地向其调用者返回结果值的(因为Runnable的run()方法不会返回结果值)
Executor接口也没有提供一种方式来追踪正在执行中的任务进程、取消正在执行的任务或者确定运行的任务什么时候结束执行
Executor无法执行一组可运行的任务
而且Executor也没有为应用程序提供一种关闭executor的方式(更为正确地关闭executor)

6.如何克服Executor的局限性
ExecutorService接口克服Executor的局限性

7.Runnable的run()方法和Callable的call()方法存在什么区别
run()无法返回结果值,而call()方法可以
run()方法无法抛出受检异常,而call()方法可以

8.判断对错:你可以从Runnable的run()方法中抛出受检和非受检的异常,但是只能从Callable的call()方法中抛出非受检的异常

Callable的call()方法中抛出受检和非受检的异常,但是只能从Runnable的run()方法中抛出非受检的异常

9.给出future的定义
future是这样一种对象,它的类实现Future接口
它代表了一种异步的计算并且提供了取消任务、返回任务结果值以及确定任务是否已经结束的方法

10.描述类Executors的newFixedThreadPool()方法
类Executors的newFixedThreadPool()方法创建一个线程池复用固定数量的线程操作一个共享的无限队列
至多有nThreads个线程同时处理任务
如果额外的任务在所有线程都活跃时被提交了,它们会在队列中等待一条可用线程
如果在executor停止之前,任何线程因为执行中的失败而终止,而后续任务的又需要执行的时候,一条新的线程会取代其位置
这些在线程池中的线程会一直存在,直到executor被显式地关闭

11.使用Executors和ExecutorService来重构下面的CountingThreads应用程序

public class CountingThreads {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                int count = 0;
                while (true) {
                    System.out.println(name + ":" + count++);
                }
            }
        };

        Thread threadA = new Thread(r);
        Thread threadB = new Thread(r);
        threadA.start();
        threadB.start();
    }
}
public class CountingThreads {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                int count = 0;
                while (true) {
                    System.out.println(name + ":" + count++);
                }
            }
        };

        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(r);
        executorService.submit(r);
    }
}

12.当你执行前面练习中CountingThreads应用程序时,你会观测到诸如pool-1-thread-1所标识的线程输出
请修改CountingThreads,以便观测名称A和B
提示:你需要使用ThreadFactory

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class CountingThreads {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                int count = 0;
                while (true) {
                    System.out.println(name + ":" + count++);
                }
            }
        };

        ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadName("A"));
        executorService.submit(r);
        executorService = Executors.newSingleThreadExecutor(new ThreadName("B"));
        executorService.submit(r);
    }
}

class ThreadName implements ThreadFactory {
    private volatile String name;

    public ThreadName(String name) {
        this.name = name;
    }

    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r, name);
    }
}