首先說一下在開發(fā)中為什么會有線程和線程池川慌。
日常開發(fā)中,如果一個操作需要好幾個步完成侣夷,其中有一兩個步非同步或事務(wù)操作横朋,比如記錄日志,那么為了提高響應(yīng)時(shí)間百拓,可以把這一兩步單獨(dú)開一個線程琴锭,由新開的線程來完成。
為什么會有線程池呢衙传?如果當(dāng)前并發(fā)巨大决帖,同一時(shí)刻會啟動多個線程來完成,那么隨著線程的增多蓖捶,服務(wù)器的內(nèi)存最終會耗盡古瓤,因此需要有線程池來管理這些線程,設(shè)置線程池的容量腺阳,新開了線程落君,都放到線程池等待,有空余資源就處理這些線程亭引。這樣就避免新開無數(shù)線程導(dǎo)致服務(wù)器資源耗盡的情況了绎速。
新建一個線程
新建一個類FirstThread
,該類實(shí)現(xiàn)Runnable接口焙蚓,并重寫Run方法纹冤,則該類就可以做為一個線程實(shí)現(xiàn)類來使用洒宝。
代碼如下:
public class FirstThread implements Runnable {
private String username;//傳參數(shù)
public FirstThread(String username) {
this.username = username;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(username + i);
}
}
}
線程啟動
首先new 當(dāng)前的FirstThread
,再new 一個Thread萌京,執(zhí)行start方法即可雁歌,比如:
public static void main(String[] args) {
FirstThread ft1 = new FirstThread("張三");
FirstThread ft2 = new FirstThread("李四");
Thread t1 = new Thread(ft1);
Thread t2 = new Thread(ft2);
t1.start();
t2.start();
}
線程池
線程池原理如下:
1、Executors.newFixedThreadPool(10)初始化一個包含10個線程的線程池executor知残;
2靠瞎、通過executor.execute方法提交20個任務(wù),每個任務(wù)打印當(dāng)前的線程名求妹;
3乏盐、負(fù)責(zé)執(zhí)行任務(wù)的線程的生命周期都由Executor框架進(jìn)行管理;
4制恍、線程池里最大有10個線程父能,如果超過10個,其余的等待净神,執(zhí)行完后再進(jìn)入線程池進(jìn)行任務(wù)執(zhí)行何吝。如果小于10個,則直接全部執(zhí)行鹃唯。
代碼如下:
/**
* Created by 孔垂云 on 2017/4/21.
*/
public class ExecutorTest {
private static Executor executor = Executors.newFixedThreadPool(10);//新建一個10個線程的線程池
/**
* 內(nèi)部類實(shí)現(xiàn)一個線程
*/
static class Task implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());//打印當(dāng)前線程的名稱
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(10));//暫停幾秒鐘
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
executor.execute(new Task());
}
}
}
Future和Callable實(shí)現(xiàn)
/**
* Created by 孔垂云 on 2017/4/21.
*/
public class FutureTest {
private static ExecutorService executor = Executors.newFixedThreadPool(10);//定義10個線程的線程池
static class Task implements Callable<String> {
@Override
public String call() throws Exception {
TimeUnit.SECONDS.sleep(1);
return "Hello Future";
}
}
public static void main(String[] args) throws Exception {
Future<String> future = executor.submit(new Task());
System.out.println("開始執(zhí)行線程:");
String ret = future.get();//獲取該線程的返回值
System.out.println("執(zhí)行結(jié)果:" + ret);
System.out.println("執(zhí)行完畢");
executor.shutdown();
}
}
在實(shí)際業(yè)務(wù)場景中岔霸,F(xiàn)uture和Callable基本是成對出現(xiàn)的,Callable負(fù)責(zé)產(chǎn)生結(jié)果俯渤,F(xiàn)uture負(fù)責(zé)獲取結(jié)果呆细。
1、Callable接口類似于Runnable八匠,只是Runnable沒有返回值絮爷。
2、Callable任務(wù)除了返回正常結(jié)果之外梨树,如果發(fā)生異常坑夯,該異常也會被返回,即Future可以拿到異步執(zhí)行任務(wù)各種結(jié)果抡四;
3柜蜈、Future.get方法會導(dǎo)致主線程阻塞,直到Callable任務(wù)執(zhí)行完成指巡;
4淑履、線程都執(zhí)行完畢后,執(zhí)行executor.shutdown();
藻雪,關(guān)閉主進(jìn)程秘噪。