1、java中為什么要使用多線程
使用多線程,可以把一些大任務分解成多個小任務來執行,多個小任務之間互不影像,同時進行,這樣,充分利用了cpu資源。
2、java中簡單的實現多線程的方式
繼承Thread類,重寫run方法;
class MyTread extends Thread{
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
實現Runable接口,實現run方法;
class MyRunnable implements Runnable{
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
class ThreadTest {
public static void main(String[] args) {
MyTread thread = new Mythread();
thread.start(); //開啟一個線程
MyRunnable myRunnable = new MyRunnable();
Thread runnable = new Thread(myRunnable);
runnable.start(); //開啟一個線程
}
}
3、java線程的狀態
創建:當new了一個線程,並沒有調用start之前,線程處於創建狀態;
就緒:當調用了start之后,線程處於就緒狀態,這是,線程調度程序還沒有設置執行當前線程;
運行:線程調度程序執行到線程時,當前線程從就緒狀態轉成運行狀態,開始執行run方法里邊的代碼;
阻塞:線程在運行的時候,被暫停執行(通常等待某項資源就緒后在執行,sleep、wait可以導致線程阻塞),這是該線程處於阻塞狀態;
死亡:當一個線程執行完run方法里邊的代碼或調用了stop方法后,該線程結束運行
4、為什么要引入線程池
當我們需要的並發執行線程數量很多時,且每個線程執行很短的時間就結束了,這樣,我們頻繁的創建、銷毀線程就大大降低了工作效率(創建和銷毀線程需要時間、資源)。
java中的線程池可以達到這樣的效果:一個線程執行完任務之后,繼續去執行下一個任務,不被銷毀,這樣線程利用率提高了。
5、java中的線程池(ThreadPoolExecutor)
說起java中的線程池,就想到java.util.concurrent.ThreadPoolExecutor。ThreadPoolExecutor類是java線程池中的核心類。他的實現方式有四種:
public class ThreadPoolExecutor extends AbstractExecutorService {
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
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;
}
通過ThreadPoolExecutor類的源碼可以看出,ThreadPoolExecutor類繼承AbstractExecutorService,提供四個構造方法,通過構造方法可以看出前面三個最終掉了最后一個
下面介紹下構造方法中的參數:
corePoolSize:線程池的大小。線程池創建之后不會立即去創建線程,而是等待線程的到來。當當前執行的線程數大於改值是,線程會加入到緩沖隊列;
maximumPoolSize:線程池中創建的最大線程數;
keepAliveTime:空閑的線程多久時間后被銷毀。默認情況下,改值在線程數大於corePoolSize時,對超出corePoolSize值得這些線程起作用。
unit:TimeUnit枚舉類型的值,代表keepAliveTime時間單位,可以取下列值:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小時
TimeUnit.MINUTES; //分鍾
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //納秒
workQueue:阻塞隊列,用來存儲等待執行的任務,決定了線程池的排隊策略,有以下取值:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
threadFactory:線程工廠,是用來創建線程的。默認new Executors.DefaultThreadFactory();
handler:線程拒絕策略。當創建的線程超出maximumPoolSize,且緩沖隊列已滿時,新任務會拒絕,有以下取值:
ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常。
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)
ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務
以下是具體的實現方式:
//默認策略。使用該策略時,如果線程池隊列滿了丟掉這個任務並且拋出RejectedExecutionException異常
class AbortPolicy implements RejectedExecutionHandler{
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
executor.toString());
}
}
//如果線程池隊列滿了,會直接丟掉這個任務並且不會有任何異常
class DiscardPolicy implements RejectedExecutionHandler{
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
}
}
//丟棄最老的,會將最早進入隊列的任務刪掉騰出空間,再嘗試加入隊列
class DiscardOldestPolicy implements RejectedExecutionHandler{
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
//移除隊頭元素
executor.getQueue().poll();
//再嘗試入隊
executor.execute(r);
}
}
}
//主線程會自己去執行該任務,不會等待線程池中的線程去執行
class CallerRunsPolicy implements RejectedExecutionHandler{
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
//直接執行run方法
r.run();
}
}
}
以下是ThreadPoolExecutor具體的繼承結構
public abstract class AbstractExecutorService implements ExecutorService {
}
這是一個抽象類,實現了ExecutorService接口,並實現了ExecutorService里邊的方法,下面看下ExecutorService接口的具體實現
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
ExecutorService繼承Executor接口,下面是Executor接口的具體實現
public interface Executor {
void execute(Runnable command);
}
Executor接口是頂層接口,只聲明了一個execute方法,該方法是用來執行傳遞進來的任務的。
回過頭來,咱么重新看ThreadPoolExecutor類,改類里邊有以下兩個重要的方法:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}else if (!addWorker(command, false))
reject(command);
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
execute()方法是Executor中聲明的方法,在ThreadPoolExecutor有了具體的實現,這個方法是ThreadPoolExecutor的核心方法,
通過這個方法可以向線程池提交一個任務,交由線程池去執行
submit()方法是ExecutorService中聲明的方法,在AbstractExecutorService中進行了實現,Executor中並沒有對其進行重寫。從實現中可以看出,submit方法最終也調用了execute
方法,也是執行一個人去,但submit方法可以返回執行結果,利用Future來獲取任務執行結果。
6、Spring中的線程池
Spring中的線程池是由ThreadPoolTaskExecutor類來實現的。該類的實現原理最終也是調用了java中的ThreadPoolExecutor類中的一些方法。具體的實現讀者可以自己去翻閱Spring
的源碼,這里筆者就不羅列了。我們看下ThreadPoolTaskExecutor的初始化。
ThreadPoolTaskExecutor有兩種常用的有兩種初始化方式:xml配置,java代碼初始化
xml配置:
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="keepAliveSeconds" value="200" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="20" />
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
看過上面的內容,讀者應該很清楚上面的一些參數代表的意思了吧。筆者在這里不一一去解釋了。
public MyThreadPoolTaskExecutor {
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
private void test(){
taskExecutor.execute(new Runnable(){
@Override
public void run() {
//執行的代碼
}});
}
}
Java代碼初始化:
private void test2(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(15);
executor.setKeepAliveSeconds(1);
executor.setQueueCapacity(5);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
executor.execute(new Runnable(){
@Override
public void run() {
//執行的代碼
}
});
}
