通過繼承自Thread實(shí)現(xiàn)線程
通過繼承Thread類自定義一個(gè)線程類谷誓,并重寫run()方法:
//通過繼承Thread類實(shí)現(xiàn)一個(gè)線程
public class MyThread extends Thread {
@Override
public void run() {
Log.d("TAG",Thread.currentThread().getName()+"通過繼承實(shí)現(xiàn)線程");//打印出當(dāng)前線程的名稱
}
}
實(shí)例化一個(gè)自定義的線程對(duì)象,進(jìn)行測(cè)試:
public void btnClick(View view){
testThread();
}
public void testThread() {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
//啟動(dòng)線程
mt1.start();
mt2.start();
}
終端輸出:
03-28 13:21:18.290 7164-7311/com.example.felix.thread_andorid D/TAG: Thread-156通過繼承實(shí)現(xiàn)接口
03-28 13:21:18.298 7164-7310/com.example.felix.thread_andorid D/TAG: Thread-155通過繼承實(shí)現(xiàn)接口
通過實(shí)現(xiàn)一個(gè)接口實(shí)現(xiàn)一個(gè)線程
public class MyRunable implements Runnable {
@Override
public void run() {
Log.d("TAG",Thread.currentThread().getName()+"通過接口實(shí)現(xiàn)線程");//打印出當(dāng)前線程的名稱
}
}
實(shí)例化一個(gè)自定義的線程對(duì)象统扳,以便進(jìn)行測(cè)試。
public void testRunnable() {
MyRunable mr1 = new MyRunable();
MyRunable mr2 = new MyRunable();
//
Thread th1 = new Thread(mr1);
Thread th2 = new Thread(mr2);
th1.start();
th2.start();
}
終端輸出:
03-28 13:29:36.734 13129-13338/com.example.felix.thread_andorid D/TAG: Thread-159通過接口實(shí)現(xiàn)線程
03-28 13:29:36.737 13129-13339/com.example.felix.thread_andorid D/TAG: Thread-160通過接口實(shí)現(xiàn)線程
多個(gè)代理賣火車票實(shí)例
public class SaleTicket implements Runnable {
private int ticketNum=20;//火車票總數(shù)
@Override
public void run() {
while (true) {
//線程同步
synchronized (this){
if (ticketNum>0){
Log.d("TAG",Thread.currentThread().getName()+"剩余火車票"+ticketNum+"張");
ticketNum--;
}
else {
break;
}
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
定義測(cè)試方法:
public void saleTicket(){
SaleTicket saleTicket = new SaleTicket();
//多個(gè)線程操作同一個(gè)目標(biāo)對(duì)象
Thread tr1 = new Thread(saleTicket,"A代理");
Thread tr2 = new Thread(saleTicket,"B代理");
Thread tr3 = new Thread(saleTicket,"C代理");
Thread tr4 = new Thread(saleTicket,"D代理");
tr1.start();
tr2.start();
tr3.start();
tr4.start();
}
終端輸出:
03-28 13:47:42.390 24262-24442/com.example.felix.thread_andorid D/TAG: D代理剩余火車票6張
03-28 13:47:42.404 24262-24441/com.example.felix.thread_andorid D/TAG: C代理剩余火車票5張
03-28 13:47:42.590 24262-24442/com.example.felix.thread_andorid D/TAG: D代理剩余火車票4張
03-28 13:47:42.594 24262-24440/com.example.felix.thread_andorid D/TAG: B代理剩余火車票3張
03-28 13:47:42.594 24262-24439/com.example.felix.thread_andorid D/TAG: A代理剩余火車票2張
03-28 13:47:42.606 24262-24441/com.example.felix.thread_andorid D/TAG: C代理剩余火車票1張
通過繼承Thread類實(shí)現(xiàn)和通過實(shí)現(xiàn)Runnabel接口的區(qū)別:
- java屬于單繼承畅姊,存在一定的局限性咒钟;
- Runnbale接口適合于資源共享;
線程池的應(yīng)用
線程池的好處:
- 重用存在的線程若未,減少對(duì)象創(chuàng)建朱嘴,消亡的開銷,性能較好粗合;
- 可有效控制最大并發(fā)線程數(shù)萍嬉,提高系統(tǒng)資源的使用率。同時(shí)避免過多資源競(jìng)爭(zhēng)隙疚,避免浪費(fèi)壤追;
- 提供定時(shí)執(zhí)行,定期執(zhí)行供屉,單線程大诸、并發(fā)數(shù)控制等功能。
Java四種線程池
-
newCachedThreadPool:可緩存線程池贯卦,如果線程長(zhǎng)度超過處理需要资柔,可靈活回收空閑線程,若無(wú)可回收線程則創(chuàng)建一個(gè)新的線程撵割;
public void testCachThreadPool(){ ExecutorService executorService = Executors.newCachedThreadPool(); //實(shí)現(xiàn)10個(gè)并發(fā)的任務(wù) for (int i = 0; i < 10; i++) { final int index = i; executorService.execute(new Runnable() { @Override public void run() { Log.d("TAG",Thread.currentThread().getName()+" ---當(dāng)前線程 "+index); } }); } }
終端輸出:
03-28 14:09:43.623 1126-2831/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---當(dāng)前線程 0
03-28 14:09:43.637 1126-2831/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---當(dāng)前線程 3
03-28 14:09:43.649 1126-2831/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---當(dāng)前線程 6
03-28 14:09:43.657 1126-2831/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---當(dāng)前線程 8
03-28 14:09:43.664 1126-2837/com.example.felix.thread_andorid D/TAG: pool-2-thread-6 ---當(dāng)前線程 7
03-28 14:09:43.665 1126-2832/com.example.felix.thread_andorid D/TAG: pool-2-thread-2 ---當(dāng)前線程 1
03-28 14:09:43.666 1126-2836/com.example.felix.thread_andorid D/TAG: pool-2-thread-5 ---當(dāng)前線程 5
03-28 14:09:43.673 1126-2835/com.example.felix.thread_andorid D/TAG: pool-2-thread-4 ---當(dāng)前線程 4
03-28 14:09:43.679 1126-2833/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---當(dāng)前線程 2
03-28 14:09:43.682 1126-2838/com.example.felix.thread_andorid D/TAG: pool-2-thread-7 ---當(dāng)前線程 9
修改代碼:
public void testCachThreadPool(){
ExecutorService executorService = Executors.newCachedThreadPool();
//實(shí)現(xiàn)10個(gè)并發(fā)的任務(wù)
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(2000);//每執(zhí)行一次任務(wù)休息兩秒
} catch (InterruptedException e) {
e.printStackTrace();
}
final int index = i;
executorService.execute(new Runnable() {
@Override
public void run() {
Log.d("TAG",Thread.currentThread().getName()+" ---當(dāng)前線程 "+index);
}
});
}
}
終端輸出:
03-28 14:15:41.549 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 0
03-28 14:15:43.550 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 1
03-28 14:15:45.551 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 2
03-28 14:15:47.553 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 3
03-28 14:15:49.556 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 4
03-28 14:15:51.561 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 5
03-28 14:15:53.562 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 6
03-28 14:15:55.564 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 7
03-28 14:15:57.565 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 8
03-28 14:15:59.566 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---當(dāng)前線程 9
當(dāng)前我們讓每執(zhí)行一次任務(wù)休息兩秒后贿堰,我們發(fā)現(xiàn)10次并發(fā)任務(wù)的執(zhí)行過程中只使用了一個(gè)線程。這是因?yàn)閚ewCachedThreadPool能夠回收空閑的線程啡彬。
-
newFixedThreadPool: 創(chuàng)建一個(gè)定長(zhǎng)的線程池羹与,可控制線程的最大并發(fā)數(shù)故硅,超出的線程會(huì)在隊(duì)列中等待。
public void testFixedThreadPool() { ExecutorService executorService = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int index = i; executorService.execute(new Runnable() { @Override public void run() { Log.d("TAG",Thread.currentThread().getName()+" ---當(dāng)前線程 "+index); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } }
終端輸出:
03-28 14:25:26.900 11037-12323/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---當(dāng)前線程 2
03-28 14:25:26.933 11037-12321/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---當(dāng)前線程 0
03-28 14:25:26.934 11037-12322/com.example.felix.thread_andorid D/TAG: pool-2-thread-2 ---當(dāng)前線程 1
03-28 14:25:28.902 11037-12323/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---當(dāng)前線程 3
03-28 14:25:28.935 11037-12321/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---當(dāng)前線程 4
03-28 14:25:28.935 11037-12322/com.example.felix.thread_andorid D/TAG: pool-2-thread-2 ---當(dāng)前線程 5
03-28 14:25:30.903 11037-12323/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---當(dāng)前線程 6
03-28 14:25:30.936 11037-12322/com.example.felix.thread_andorid D/TAG: pool-2-thread-2 ---當(dāng)前線程 7
03-28 14:25:30.938 11037-12321/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---當(dāng)前線程 8
03-28 14:25:32.906 11037-12323/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---當(dāng)前線程 9
因?yàn)樽畲蟮木€程數(shù)被設(shè)置為3纵搁,所以是每隔兩秒執(zhí)行三個(gè)任務(wù)吃衅。直觀的表現(xiàn)是,終端每個(gè)兩秒打印出三條語(yǔ)句腾誉。
- newsingalThreadExecutor:創(chuàng)建一個(gè)單線程化的線程池徘层,它只會(huì)用唯一的工作線程來(lái)執(zhí)行任務(wù),保證任務(wù)按照指定順序(FIFO利职,LIFO趣效,優(yōu)先級(jí))執(zhí)行。
public void testSingalThread(){
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.execute(new Runnable() {
@Override
public void run() {
Log.d("TAG",Thread.currentThread().getName()+" ---當(dāng)前線程 "+index);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
程序在運(yùn)行過程中只會(huì)只用一個(gè)線程來(lái)執(zhí)行10個(gè)任務(wù)猪贪。
- newScheduledThreadPool:創(chuàng)建一個(gè)定長(zhǎng)線程池跷敬,支持定時(shí)及周期性任務(wù)執(zhí)行。
public void testScheduledThreadPool(){
Log.d("TAG","testScheduled");
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
//定時(shí)三秒以后執(zhí)行
/*schedule()方法:
* 第一個(gè)參數(shù):執(zhí)行的線程任務(wù)热押;
* 第二個(gè)參數(shù):時(shí)間量西傀;
* 第三個(gè)參數(shù):時(shí)間量的單位。
* */
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
Log.d("TAG","delay 3 seconds");
}
},3, TimeUnit.SECONDS);
}
終端輸出:
03-28 15:09:21.169 23078-23078/com.example.felix.thread_andorid D/TAG: testScheduled
03-28 15:09:24.172 23078-23224/com.example.felix.thread_andorid D/TAG: delay 3 seconds
周期性定時(shí)執(zhí)行任務(wù)
/*周期性的定時(shí)執(zhí)行*/
//定時(shí)兩秒后執(zhí)行桶癣,每個(gè)三秒再執(zhí)行一次
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Log.d("TAG","delay 3 seconds");
}
},2,3,TimeUnit.SECONDS);
scheduledExecutorService.shutdown();//關(guān)閉周期性執(zhí)行任務(wù)
終端輸出:
03-28 15:23:22.607 23078-23078/com.example.felix.thread_andorid D/TAG: testScheduled
03-28 15:23:24.609 23078-28404/com.example.felix.thread_andorid D/TAG: delay 3 seconds
03-28 15:23:27.610 23078-28404/com.example.felix.thread_andorid D/TAG: delay 3 seconds
03-28 15:23:30.609 23078-28404/com.example.felix.thread_andorid D/TAG: delay 3 seconds
03-28 15:23:33.609 23078-28404/com.example.felix.thread_andorid D/TAG: delay 3 seconds
仔細(xì)觀察每條輸出語(yǔ)句的時(shí)間拥褂。