1.防止在共享资源上产生冲突的方式
- 加锁。使用Synchronized关键字,同步加锁方法,或建立临界区;使用Lock和Atomic类;
- 根除对变量的共享。使用ThreadLocal类,此类会为每个使用相同变量的每个不同线程都创建不同的存储。即线程本地存储。
2.线程可以驱动任务,那么描述任务的方式和用驱动任务的方式分别有哪些
描述任务的方式:实现Runnable接口并编写run()方法,但此方法无返回值。如果想要任务完成是能返回一个值,那么可以实现Callable接口并编写call()方法;
驱动任务的方式:Thread类,传统方式是使用Thread来驱动Runnable对象,即
Thread t = new Thread(new Xxx());
t.start();
其中,Xxx是一个实现了Runnable接口的类。使用Thread的弊端:每个Thread都“注册”了它自己,因此确实有一个对它的引用,而且在它的任务退出其run()并死亡之前,垃圾回收器无法清除它。也就是说,每个Thread进程都会创建一个单独的执行线程,在对start()的调用完成之后,它依旧会继续存在。为避免这个问题,我们使用执行器(Executor)来管理Thread对象,从而简化并发编程。
3.关于线程池ExecutorService
在说线程池之前,先说执行器(Executor)。ExecutorService实际上是具有服务声明周期的Executor,例如关闭,而Executor则是一个执行线程的工具,它是所有线程池的最顶级的接口。Executor在客户端和任务执行之间提供了一个间接层;与客户端直接执行任务不同,这个中介对象将执行任务。Executor允许你管理异步任务的执行,而无须显示的管理线程的生命周期。
ExecutorService有三种常用的创建方式,它也是JDK所推崇的三种使用方式。
- Executors.newCachedThreadPool(),无界线程池,可以自动进行线程回收;
- Executors.newFixedThreadPool(int),固定大小线程池;
- Executors.newSingleThreadExecutor(),单一后台线程。
实现代码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
可以看到,上面三种创建线程池的方式都是ThreadPoolExecutor类的同一个构造方法不同参数构造的。
4.线程池ThreadPoolExecutor类参数详解
先看下这个类有几种构造方法:
看源码,前面3个其实都是调用的第4个方法,所以先看看第4个方法的源码实现:
/**
* Creates a new <tt>ThreadPoolExecutor</tt> with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the
* pool, even if they are idle.
* @param maximumPoolSize the maximum number of threads to allow in the
* pool.
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the keepAliveTime
* argument.
* @param workQueue the queue to use for holding tasks before they
* are executed. This queue will hold only the <tt>Runnable</tt>
* tasks submitted by the <tt>execute</tt> method.
* @param threadFactory the factory to use when the executor
* creates a new thread.
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached.
* @throws IllegalArgumentException if corePoolSize or
* keepAliveTime less than zero, or if maximumPoolSize less than or
* equal to zero, or if corePoolSize greater than maximumPoolSize.
* @throws NullPointerException if <tt>workQueue</tt>
* or <tt>threadFactory</tt> or <tt>handler</tt> are null.
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
总共7个参数,接下来一一介绍:
corePoolSize.
maximumPoolSize
看源码,前面3个其实都是调用的第4个方法,所以先看看第4个方法的参数都是些什么:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)