1.Thread詳解,直接看示例代碼,注釋非常詳細(xì)
package com.landon.mavs.example.concurrent;

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.landon.mavs.example.util.PrintUtil;


/** *//**
*
* 線程基礎(chǔ)示例
*
* <pre>
* 1.public class Thread implements Runnable,其實(shí)現(xiàn)了Runnable接口.且如果其構(gòu)造中傳入了Runnable
* target,則其實(shí)現(xiàn)的run直接調(diào)用target.run.否則需要覆寫run
*
* 2.其內(nèi)部定義了一個(gè)表示線程狀態(tài)的枚舉
* {@link Thread.State}.包括NEW/RUNNABLE/BLOCKED/WAITING/TIMED_WAITING/TERMINATED
* 6個(gè)狀態(tài).
*
* 3.其內(nèi)部還定義了一個(gè)接口{@link java.lang.Thread.UncaughtExceptionHandler}
* ,用來表示線程因未捕獲的異常而突然終止時(shí),調(diào)用處理程序的接口. 接口中只有一個(gè)方法:void uncaughtException(Thread t,
* Throwable e).
* {@link Thread#setUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)}
* {@link Thread#getUncaughtExceptionHandler()}
* {@link Thread#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)}},該方法是一個(gè)靜態(tài)方法.
* ->{@link ThreadGroup#uncaughtException(Thread, Throwable)}
*
* 4.其內(nèi)部定義了3個(gè)線程優(yōu)先級(jí)常量,分別是{@link Thread#MIN_PRIORITY},{@link Thread#NORM_PRIORITY},{@link Thread#MAX_PRIORITY}
* ->三個(gè)常量值分別是1,5,10
* </pre>
*
* @author landon
*
*/

public class ThreadBaseExample
{
private static final Logger LOGGER = LoggerFactory
.getLogger(ThreadBaseExample.class);


public static void main(String[] args)
{
// public Thread(ThreadGroup group, Runnable target, String name,long
// stackSize)
// 1.Thread構(gòu)造方法最多可傳入4個(gè)參數(shù),分別是線程組/run方法的目標(biāo)任務(wù)/新線程的名稱/新線程的預(yù)期堆棧大小,為0表示忽略該參數(shù)
// 2.Thread的其他7個(gè)構(gòu)造方法也均是對這4個(gè)參數(shù)直接或間接的指定
// 從源碼看:
// 1.其內(nèi)部實(shí)現(xiàn)均是調(diào)用了私有的private void init(ThreadGroup g, Runnable target,
// String name,long stackSize)方法.
// 2.構(gòu)造如果未指定線程名字,則會(huì)初始化為"Thread-" +
// nextThreadNum(),nextThreadNum則為線程的一個(gè)內(nèi)部靜態(tài)計(jì)數(shù)器,從0開始(synchronized)
// 3.如果未指定線程組group.則首先設(shè)置group為SecurityManager的線程組,如果還為空的話,則設(shè)置為當(dāng)前調(diào)用線程所屬的線程組.
// 同時(shí)isDaemon/priority屬性設(shè)置和當(dāng)前調(diào)用線程一致.
// 4.stackSize這個(gè)參數(shù),從API
// doc來看:該參數(shù)的作用具有高度的平臺(tái)依賴性(在某些平臺(tái)上,該參數(shù)可能不會(huì)起任何作用).因?yàn)槭褂盟鼤r(shí)要非常小心(所以API說要Java實(shí)現(xiàn)者文檔化該參數(shù)的實(shí)現(xiàn)行為).
// (可參考JVM參數(shù)-Xss來理解stackSize).
// 5.線程的tid也是根據(jù)nextThreadID生成,即也是一個(gè)內(nèi)部計(jì)時(shí)器,從1開始(synchronized),區(qū)別于name的計(jì)數(shù)器從0開始(一個(gè)是++i,一個(gè)是i++)

try
{
Thread t1 = new Thread(null, null, null, 0);
// 運(yùn)行程序,發(fā)現(xiàn)報(bào)了一個(gè)空指針異常,因?yàn)榈谌齻€(gè)參數(shù)name傳了null.而在Thread的源碼中是用char[]存儲(chǔ)name的,即在init要對name進(jìn)行進(jìn)行name.toCharArray()操作.
// 所以就報(bào)了空指針.所以如果用上面的構(gòu)造函數(shù),必須指定name.即name要么指定不為空,要么不指定自生成
LOGGER.debug(
"t1.name:{},t1.groupName:{},t1.id:{},t1.isDaemon:{},t1.priority:{}",
t1.getName(), t1.getThreadGroup().getName(), t1.getId(),
t1.isDaemon(), t1.getPriority());

} catch (Exception e)
{
LOGGER.warn("", e);
}

// 其內(nèi)部調(diào)用:init(null, null, "Thread-" + nextThreadNum(), 0)
Thread t2 = new Thread();
// 輸出:t2.name:Thread-0,t2.groupName:main,t2.id:9,t2.isDaemon:false,t2.priority:5
// 問題:為什么t2.id什么為9呢?因?yàn)榫€程id從1開始,也就是說已經(jīng)初始化了8個(gè)線程
// landon:1.因?yàn)閖vm程序啟動(dòng)后,會(huì)啟動(dòng)一些守護(hù)線程(JVM內(nèi)部線程).從下面的systemGroup輸出即可了解大概.
// 2.用jstack查看了一下,另外啟動(dòng)的三個(gè)線程是Low Memory Detector/C2 CompilerThread1/C2
// CompilerThread0
LOGGER.debug(
"t2.name:{},t2.groupName:{},t2.id:{},t2.isDaemon:{},t2.priority:{},t2.state:{}",
t2.getName(), t2.getThreadGroup().getName(), t2.getId(),
t2.isDaemon(), t2.getPriority(), t2.getState());
// 獲得系統(tǒng)線程組
ThreadGroup systemGroup = t2.getThreadGroup().getParent();
Thread[] totalThreads = new Thread[systemGroup.activeCount()];
systemGroup.enumerate(totalThreads);
// 輸出: [Thread[Reference Handler,10,system], Thread[Finalizer,8,system],
// Thread[Signal Dispatcher,9,system], Thread[Attach Listener,5,system],
// Thread[main,5,main]
// 從輸出可以看出,系統(tǒng)線程組下有多個(gè)活動(dòng)線程,當(dāng)然有一些是守護(hù)線程,除了main線程外,其余均是守護(hù)線程
LOGGER.debug("application.totalThreads:{}",
Arrays.toString(totalThreads));
// 從輸出可以看出,主線程main的id為1,即為初始化的第一個(gè)線程,然后是Reference
// Handler(2)/Finalizer(3)/Signal Dispatcher(4)/Attach Listener(5)
// 這5個(gè)均是jvm內(nèi)部線程

for (Thread t : totalThreads)
{
LOGGER.debug("{} .id:{}", t.getName(), t.getId());
}
ThreadGroup[] totalGroups = new ThreadGroup[systemGroup
.activeGroupCount()];
systemGroup.enumerate(totalGroups);
// 輸出:[java.lang.ThreadGroup[name=main,maxpri=10]] 也就是說系統(tǒng)線程組下只有一個(gè)主線程組
LOGGER.debug("application.totalGroups:{}", Arrays.toString(totalGroups));

Thread t3 = new Thread(new BaseExampleTask(), "t3");
// Thread#public synchronized void start()
// 使該線程開始執(zhí)行(結(jié)果是兩個(gè)線程并發(fā)的執(zhí)行,即當(dāng)前調(diào)用start的線程以及另一個(gè)執(zhí)行run的線程)
// 不能多次啟動(dòng)一個(gè)線程/當(dāng)線程已經(jīng)結(jié)束執(zhí)行后,不能再重新啟動(dòng),否則會(huì)拋出java.lang.IllegalThreadStateException
// 這個(gè)很重要.不要試圖有"重啟線程"這個(gè)想法.如果想復(fù)用線程,則任務(wù)可采用while(flag)形式,詳細(xì)可參考線程池實(shí)現(xiàn)
// 可從os上來理解線程的本質(zhì)(假如"線程可重啟的話",會(huì)有很多問題.1.拋出異常的任務(wù)你重啟有毛用 2.重啟后如何再提交任務(wù)?
// 3.何時(shí)銷毀線程?內(nèi)存泄露? 等等。。) // 此純屬landon個(gè)人猜測
// 從源碼上看:
// 1.判斷當(dāng)前狀態(tài),如果不是"NEW"或者this !=
// me(線程初始化init的時(shí)候,會(huì)將this賦值給me),則拋出IllegalThreadStateException
// 2.group.add(this)
// 將自身加入到所屬的線程組中->即只有執(zhí)行了start方法才會(huì)將線程加入到所屬的線程組中,這里是main線程組
t3.start();

try
{
LOGGER.debug("t3.state:{}", t3.getState());
// 從輸出可以看到,拋出了IllegalThreadStateException.因?yàn)榇藭r(shí)state已經(jīng)是RUNNABLE了
t3.start();

} catch (Exception e)
{
LOGGER.warn("", e);
}

try
{
// 主線程等待t3執(zhí)行完畢
t3.join();

} catch (Exception e)
{
LOGGER.warn("", e);
}

try
{
LOGGER.debug("t3.state:{}", t3.getState());
// 從輸出可以看到,拋出了IllegalThreadStateException.因?yàn)榇藭r(shí)state已經(jīng)是TERMINATED了
t3.start();

} catch (Exception e)
{
LOGGER.warn("", e);
}

// Thread#public static int activeCount()
// 該方法是一個(gè)靜態(tài)方法.返回當(dāng)前調(diào)用線程所屬的線程組中活動(dòng)線程的數(shù)目,而當(dāng)前調(diào)用線程為main
LOGGER.debug("main.group.activeCount:{}", Thread.activeCount());
// Thread#public final void checkAccess()
// 如果有SecurityManager,則調(diào)用security.checkAccess(this)
// {@link SecurityManager#checkAccess(Thread t)}
// 即判斷當(dāng)前的調(diào)用線程是否有權(quán)限修改該線程,如果不允許則拋出SecurityException
// 在setName/setPriority/setDaemon方法的實(shí)現(xiàn)中都均調(diào)用了checkAccess()方法,如果無權(quán)限修改則拋出SecurityException,則不會(huì)執(zhí)行后續(xù)修改邏輯
t3.checkAccess();
// Thread#public final void setName(String name) 改變線程名稱
t3.setName("t-modify-3");
// Thread# 更改的線程優(yōu)先級(jí)
// 從源碼看:
// 1.checkAccess 判斷是否有權(quán)限修改
// 2.判斷參數(shù)的合法化,即參數(shù)必須要在[MIN_PRIORITY,MAX_PRIORITY],否則拋出IllegalArgumentException
// 3.判斷所屬線程組的最大允許優(yōu)先級(jí),線程優(yōu)先級(jí)被設(shè)置為指定的newPriority和所屬線程組的最大允許優(yōu)先級(jí)中較小的一個(gè){@link
// ThreadGroup#setMaxPriority(int pri)}
// ThreadGroup默認(rèn)的maxPriority為parent的maxPriority,main的parent為system線程組,而system線程組的maxPriority為10
t3.setPriority(Thread.MIN_PRIORITY);
// 從這里輸出看發(fā)現(xiàn)t3的優(yōu)先級(jí)并沒有被修改,還是5.why?看下面的解釋(因?yàn)榫€程已經(jīng)運(yùn)行結(jié)束.所屬線程組已經(jīng)變?yōu)榱薾ull.所以設(shè)置優(yōu)先級(jí)失敗)
LOGGER.debug("t3.name:{},t3.priority:{}", t3.getName(),
t3.getPriority());
// Thread#public final ThreadGroup getThreadGroup()
// 返回該線所屬的線程組.注意,如果該線程已經(jīng)停止運(yùn)行,則該方法返回null.
// 從輸出看,因?yàn)榍懊娴拇a調(diào)用了join,即t3肯定已經(jīng)結(jié)束了.所以輸出拋出了空指針異常
// 從源碼看:
// 1.Thread內(nèi)部有一個(gè)私有的exit方法.private void exit().
// 該方法應(yīng)該是被系統(tǒng)調(diào)用,即線程真正退出的時(shí)候給線程一個(gè)清理的機(jī)會(huì)
// 2.該方法的實(shí)現(xiàn)中,如果group不為null,則從group中移除自身并設(shè)置group為null.

try
{
LOGGER.debug("mainGroup.maxPriority:{}", t3.getThreadGroup()
.getMaxPriority());

} catch (Exception e)
{
LOGGER.warn("", e);
}

// Thread#public static native Thread currentThread() 靜態(tài)方法
// 返回當(dāng)前正在執(zhí)行調(diào)用的線程對象的引用,即正在執(zhí)行這句代碼的線程 而當(dāng)前調(diào)用線程為主線程main
LOGGER.debug("currentThread.name:{}", Thread.currentThread().getName());
// Thread#public static void dumpStack() 靜態(tài)方法 將當(dāng)前線程的堆棧跟蹤打印至標(biāo)準(zhǔn)錯(cuò)誤流
// 源碼實(shí)現(xiàn):new Exception("Stack trace").printStackTrace();
Thread.dumpStack();
// 相當(dāng)于Thread.dumpStack()
new Exception("dump stack trace").printStackTrace();

Thread[] mainActiveThreads = new Thread[Thread.activeCount()];
// Thread#public static int enumerate(Thread tarray[]) 靜態(tài)方法
// 將當(dāng)前調(diào)用的線程組及其子組的另一個(gè)活動(dòng)線程復(fù)制到指定的數(shù)組
// 源碼實(shí)現(xiàn):return currentThread().getThreadGroup().enumerate(tarray)
// {@link ThreadGroup#enumerate(Thread list[])}
Thread.enumerate(mainActiveThreads);
LOGGER.debug("mainActiveThreads:{}", Arrays.toString(mainActiveThreads));

// Thread#public static Map<Thread, StackTraceElement[]>
// getAllStackTraces()
// 靜態(tài)方法 返回所有活動(dòng)線程的一個(gè)堆棧跟蹤的map.每個(gè)線程的堆棧跟蹤至代表一個(gè)快照
// 源碼看:
// 1.檢查SecurityManager,即是否有GET_STACK_TRACE_PERMISSION/MODIFY_THREADGROUP_PERMISSION的權(quán)限
// 2.調(diào)用Thread內(nèi)部的私有方法 private native static Thread[] getThreads()
// 獲取線程列表快照
// 3.調(diào)用Thread內(nèi)部私有方法private native static StackTraceElement[][]
// dumpThreads(Thread[] threads) 執(zhí)行dump
// 4.StackTraceElement[][]轉(zhuǎn)為map
Map<Thread, StackTraceElement[]> mainActiveStackTraceMap = Thread
.getAllStackTraces();
for (Entry<Thread, StackTraceElement[]> entry : mainActiveStackTraceMap

.entrySet())
{
// 從輸出可以看出:如果當(dāng)前沒有線程的堆棧跟蹤信息,則反返回一個(gè)零長度數(shù)組而非null.因?yàn)镻rintUtil.printStackTrace未報(bào)空指針異常
LOGGER.debug("mainActiveStackTraceMap.thread.name:{}", entry
.getKey().getName());
PrintUtil.printStackTrace(entry.getValue(), System.err);
}

// Thread#public StackTraceElement[] getStackTrace()
// 返回一個(gè)表示該線程堆棧轉(zhuǎn)儲(chǔ)的堆棧跟蹤元素?cái)?shù)組.如果該線程尚未啟動(dòng)或者已經(jīng)終止,則該該方法返回一個(gè)零長度數(shù)組.{@link
// Thread#EMPTY_STACK_TRACE},是一個(gè)private static final
// StackTraceElement[].數(shù)組的第一個(gè)元素代表堆棧頂,其是該序列中最新的方法調(diào)用,最后一個(gè)元素代表堆棧底,是該序列中最舊的方法調(diào)用
// 從源碼看:
// 1.會(huì)檢查this和Thread.currentThread是否一致,如果不一致,則調(diào)用SecurityManager是否有GET_STACK_TRACE_PERMISSION
// ->判斷線程是否alive,如果非alive,則返回EMPTY_STACK_TRACE
// ->調(diào)用dumpThreads(new Thread[] {this})
// 2.如果this == Thread.currentThread,則直接return (new
// Exception()).getStackTrace()
StackTraceElement[] mainThreadStackTraceElements = Thread
.currentThread().getStackTrace();
PrintUtil.printStackTrace(mainThreadStackTraceElements, System.err);

// Thread#public ClassLoader getContextClassLoader()
// 返回該線程的上下文Classloader.上下文Classloader由線程創(chuàng)建者提供,供運(yùn)行于該線程中的代碼在加載類和資源時(shí)使用.如果未設(shè)定,則默認(rèn)為父線程的Classloader上下文.
// 原始線程的上下文Classloader通常設(shè)定為用于加載應(yīng)用程序的類加載器.
// 從輸出的結(jié)果看:返回的是sun.misc.Launcher$AppClassLoader
// 從源碼看:如果有SecurityManager且調(diào)用者的類加載器不為null且也不同于其上下文類加載器正在被請求的線程上下文類加載器的祖先,則check是否有GET_CLASSLOADER_PERMISSION的權(quán)限
// {@link Thread#setContextClassLoader(ClassLoader cl)}
ClassLoader mainContextClassLoader = Thread.currentThread()
.getContextClassLoader();
LOGGER.debug("mainContextClassLoader:{}", mainContextClassLoader);

// Thread#public static UncaughtExceptionHandler
// getDefaultUncaughtExceptionHandler()
// 靜態(tài)方法,返回線程由于未捕獲到異常而突然終止時(shí)調(diào)用的默認(rèn)處理程序{@link
// Thread#setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler
// eh)}
// 從源碼上看:
// 1.當(dāng)線程由于未捕獲到異常而突然終止時(shí),是首先調(diào)用{link
// Thread#getUncaughtExceptionHandler()},在私有的方法dispatchUncaughtException(Throwable
// e)調(diào)用
// 2.getUncaughtExceptionHandler首先判斷線程自身的uncaughtExceptionHandler是否為null,如果不為null,則直接返回當(dāng)前;否則返回group.
// =>因?yàn)門hreadGroup implements Thread.UncaughtExceptionHandler
// 3.在ThreadGroup#uncaughtException方法中,判斷parent是否為null,如果不為null則調(diào)用parent.uncaughtException方法.
// 否則則調(diào)用Thread.getDefaultUncaughtExceptionHandler()
// 也就說線程的這個(gè)靜態(tài)DefaultUncaughtExceptionHandler是在線程自身未指定handler,線程的線程組系列(包括父線程組)也未指定uncaughtException方法,則才會(huì)轉(zhuǎn)至這個(gè)默認(rèn)的handler
UncaughtExceptionHandler defaultUncaughtExceptionHandler = Thread
.getDefaultUncaughtExceptionHandler();
// 從輸出看,現(xiàn)在為null
LOGGER.debug("defaultUncaughtExceptionHandler:{}",
defaultUncaughtExceptionHandler);

// Thread#public static void
// setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)
// 注意一個(gè)問題:不要設(shè)置handler為線程的ThreadGroup對象,否則會(huì)引起無限遞歸.
// {@link ThreadGroup#uncaughtException(Thread t, Throwable e)}
Thread.setDefaultUncaughtExceptionHandler(new ExampleDefaultUncaughtExceptionHandler());

// 啟動(dòng)了一個(gè)拋出異常的任務(wù).從輸出看,執(zhí)行了ExampleDefaultUncaughtExceptionHandler的uncaughtException方法
Thread t4 = new Thread(new ExampleExceptionTask(), "t4");
t4.start();

// Thread#public UncaughtExceptionHandler getUncaughtExceptionHandler()
// return uncaughtExceptionHandler != null ? uncaughtExceptionHandler :
// group;
// 輸出:t4.uncaughtExceptionHandler:java.lang.ThreadGroup[name=main,maxpri=10]
// 從輸出看出,返回的是group
LOGGER.debug("t4.uncaughtExceptionHandler:{}",
t4.getUncaughtExceptionHandler());

Thread t5 = new Thread(new ExampleExceptionTask(), "t-5");
// Thread#setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
// 從輸出看,拋出異常時(shí)執(zhí)行了{(lán)@link AUncaughtExcaptionHandler#uncaughtException}方法
// 源碼實(shí)現(xiàn)中首先調(diào)用了 checkAccess(),即是否有權(quán)限修改
t5.setUncaughtExceptionHandler(new AUncaughtExcaptionHandler());
t5.start();

// 從輸出看:com.landon.mavs.example.concurrent.ThreadBaseExample$AUncaughtExcaptionHandle
// 即處處了線程設(shè)置的handler
LOGGER.debug("t5.uncaughtExceptionHandler:{}",
t5.getUncaughtExceptionHandler());

Thread t7 = new Thread(new ExampleDaemonTask(), "t7");
t7.setDaemon(true);
t7.start();

try
{
// 這里主線程等待t7結(jié)束.因?yàn)橹骶€程是用戶線程,所以t7可完全結(jié)束.
t7.join();

} catch (Exception e)
{
LOGGER.warn("t7.join.exception.", e);
}

Thread t6 = new Thread(new ExampleDaemonTask(), "t6");
// Thread#public final void setDaemon(boolean on)
// 將線程標(biāo)記為守護(hù)線程或者用戶線程.當(dāng)正在運(yùn)行的線程都是守護(hù)線程時(shí),Java虛擬機(jī)退出
// 注意該方法必須在啟動(dòng)線程前調(diào)用
// 源碼上看:1.checkAccess
// 2.判斷isAlive(),如果alive,則拋出IllegalThreadStateException 3.設(shè)置daemon屬性為參數(shù)
t6.setDaemon(true);
// 從輸出看,設(shè)置t6為守護(hù)線程后,任務(wù)只輸出了begin,未輸出end或者異常輸出.也就是說虛擬機(jī)直接退出了.未執(zhí)行打斷守護(hù)線程類似的邏輯.
t6.start();

Thread t8 = new Thread("t8");
// Thread#public String toString() 返回該線程的字符串表示形式
// 返回:Thread[name,priority,group.name],如果group為null,則沒有g(shù)roup.name
LOGGER.debug("t8:{}", t8.toString());

// 靜態(tài)方法, 暫停當(dāng)前正在執(zhí)行的線程對象,并執(zhí)行其他線程
// yield()只是使當(dāng)前線程重新回到可執(zhí)行狀態(tài),所以執(zhí)行yield()的線程有可能在進(jìn)入到可執(zhí)行狀態(tài)后馬上又被執(zhí)行
// yield()只能使同優(yōu)先級(jí)的線程有執(zhí)行的機(jī)會(huì)
Thread.yield();

// 從輸出大致可以看到,每到2的倍數(shù)時(shí)就切換了一下線程

for (int i = 0; i < 2; i++)
{
new YieldThread("yt-" + i).start();
}

// Thread#public final native boolean isAlive() 測試線程是否處于活動(dòng)狀態(tài)
// 如果線程已經(jīng)啟動(dòng)且尚未終止則返回true
LOGGER.debug("t6.isAlive:{}", t6.isAlive());// true 已啟動(dòng),但是為結(jié)束
LOGGER.debug("t8.isAlive:{}", t8.isAlive());// false,因?yàn)檫€未啟動(dòng)
LOGGER.debug("t7.isAlive:{}", t7.isAlive());// false 已啟動(dòng),但是已結(jié)束

// 測試Thread#holdsLock(Object obj)方法
HoldsLockThread hlt = new HoldsLockThread();
hlt.start();
}


private static class BaseExampleTask implements Runnable
{

@Override

public void run()
{
LOGGER.debug("BaseExampleTask begin");

// sleep模擬任務(wù)耗時(shí)

try
{
Thread.sleep(3 * 1000);

} catch (Exception e)
{
LOGGER.debug("BaseExampleTask was interrupted.");
}

LOGGER.debug("BaseExampleTask end");
}

}


private static class ExampleExceptionTask implements Runnable
{

@Override

public void run()
{
throw new RuntimeException();
}

}

private static class ExampleDefaultUncaughtExceptionHandler implements

UncaughtExceptionHandler
{

@Override

public void uncaughtException(Thread t, Throwable e)
{
LOGGER.debug(String.format("thread.name:%s", t.getName()), e);
}
}

private static class AUncaughtExcaptionHandler implements

UncaughtExceptionHandler
{

@Override

public void uncaughtException(Thread t, Throwable e)
{
LOGGER.debug("this a thread:{} UncaughtExcaptionHandler.", t);
LOGGER.warn("", e);
}
}

// 一個(gè)Daemon任務(wù)

private static class ExampleDaemonTask implements Runnable
{

@Override

public void run()
{
Thread curThread = Thread.currentThread();

LOGGER.debug("ExampleDaemonTask" + "[" + curThread.getName() + "]"
+ " begin");

try
{
// 這里讓sleep時(shí)間長了一下,看一下守護(hù)任務(wù)是否被終止
TimeUnit.SECONDS.sleep(10);

} catch (InterruptedException e)
{
LOGGER.warn("ExampleDaemonTask was interrupted.", e);
}

LOGGER.debug("ExampleDaemonTask" + "[" + curThread.getName() + "]"
+ " end");
}
}


private static class YieldThread extends Thread
{

public YieldThread(String name)
{
super(name);
}

@Override

public void run()
{

for (int i = 3; i <= 10; i++)
{
LOGGER.debug(String.format("[%s]:%d", getName(), i));


if (i % 2 == 0)
{
// 執(zhí)行yield,暫停一下,讓出cpu
Thread.yield();
}
}
}
}


private static class HoldsLockThread extends Thread
{
private final Object lock = new Object();

@Override

public void run()
{

try
{
LOGGER.debug("HoldsLockThread.holdsLock:{}", holdsLock(lock));// false

synchronized (lock)
{
lock.wait(1 * 1000);
// Thread#public static native boolean holdsLock(Object obj)
// 靜態(tài)方法 當(dāng)且僅當(dāng)當(dāng)前線程在指定對象上保持監(jiān)視器鎖時(shí),才返回true
LOGGER.debug("HoldsLockThread.holdsLock:{}",
holdsLock(lock));// true
}
LOGGER.debug("HoldsLockThread.holdsLock:{}", holdsLock(lock));// false

} catch (InterruptedException e)
{
}
}
}
}

2.本篇結(jié)合jdk源碼+示例代碼詳細(xì)介紹了Thread的API.
posted on 2013-12-23 15:23
landon 閱讀(1710)
評(píng)論(0) 編輯 收藏 所屬分類:
Program