傳統使用類Thread和接口Runnable實作
- 在Thread子類覆寫的run方法中編寫運作代碼
new Thread(){
@Override
public void run(){
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }.start();
- 在傳遞給Thread對象的Runnable對象的run方法中編寫代碼
new Thread(new Runnable(){
public void run(){
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}).start();
- 總結
檢視Thread類的run()方法的源代碼,可以看到其實這兩種方式都是在調用Thread對象的run方法,如果Thread類的 run 方法沒有被覆寫,并且為該 Thread 對象設定了一個 Runnable 對象,該 run 方法會調用 Runnable 對象的run方法.
請模拟寫出雙重定時器(面試題)
class TimerTastCus extends TimerTask {
@Override
public void run() {
count = (count + 1) % 2;
System.err.println("Boob boom ");
new Timer().schedule(new TimerTastCus(), 2000 + 2000 * count);
}
}
Timer timer = new Timer(); timer.schedule(new
TimerTastCus(), 2000+2000*count);
while(true)
{
System.out.println(new Date().getSeconds());
try {
Thread.sleep(1000);
} catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
//PS:下面的代碼中的 count 變量中
// 此參數要使用在你匿名内部類中,使用 final 修飾就無法對其值進行修改,
// 隻能改為靜态變量 private static volatile int count = 0;
}
多線程的建立方式
- (1)繼承Thread類:但Thread本質上也是實作了Runnable接口的一個執行個體,它代表一個線程的執行個體,并且,啟動線程的唯一方法就是通過Thread類的 start()執行個體方法.start()方法是一個native方法,它将啟動一個心線程,并執行run()方法. 這種方式實作多線程很簡單,通過自己的類直接 exthed Thread, 并複寫run()方法,就可以啟動新線程并執行自己定義的run()方法.例如:繼承Thread類實作多線程,并且在合适的地方啟動線程.
- (2)實作Runnable接口的方式實作多線程,并且執行個體化Thread,傳入自己的Thread執行個體,調用run( )方法
- (3)使用ExecutorService、Callable、Future實作有傳回結果的多線程:ExecutorService、Callable、Future這 個 對 象 實際 上 都是屬 于 Executor 框 架中 的 功 能 類。 想 要詳細 了 解 Executor 架構 的 可 以 通路http://www.javaeye.com/topic/366591 ,這裡面對該架構做了很詳細的解釋。傳回結果的線程是在JDK1.5中引入的新特征,确實很實用,有了這種特征我就不需要再為了得到傳回值而大費周折了,而且即便實作了也可能漏洞百出。可傳回值的任務必須實作Callable接口,類似的,無傳回值的任務必須Runnable接口。執行Callable任務後,可以擷取一個 Future 的對象,在該對象上調用 get 就可以擷取到 Callable 任務傳回的 Object 了,再結合線程池接口ExecutorService就可以實作傳說中有傳回結果的多線程了。下面提供了一個完整的有傳回結果的多線程測試例子,在JDK1.5下驗證過沒問題可以直接使用.
在 java 中 wait 和 sleep 方法的不同?
- 最大的不同是在等待時wait會釋放鎖,而sleep一直持有鎖。wait通常被用于線程間互動,sleep通常被用于暫停執行。
synchronized 和 volatile 關鍵字的作用
- 一旦一個共享變量(類的成員變量、類的靜态成員變量)被volatile修飾之後,那麼就具備了兩層語義:
- 1)保證了不同線程對這個變量進行操作時的可見性,即一個線程修改了某個變量的值,這新值對其他線程來說是立即可見的。
-
2)禁止進行指令重排序。
volatile本質是在告訴jvm目前變量在寄存器(工作記憶體)中的值是不确定的,需要從主存中讀取;
synchronized則是鎖定目前變量,隻有目前線程可以通路該變量,其他線程被阻塞住。
1.volatile僅能使用在變量級别;
synchronized則可以使用在變量、方法、和類級别的
2.volatile僅能實作變量的修改可見性,并不能保證原子性;
synchronized則可以保證變量的修改可見性和原子性
3.volatile不會造成線程的阻塞;
synchronized可能會造成線程的阻塞。
4.volatile标記的變量不會被編譯器優化;
synchronized标記的變量可以被編譯器優化