天天看點

Java-多線程總結(面試題)

傳統使用類Thread和接口Runnable實作

  1. 在Thread子類覆寫的run方法中編寫運作代碼
new Thread(){ 
 @Override  
 public void run(){  
  while(true){    
  try {  
     Thread.sleep(2000);   
      } catch (InterruptedException e) {  
         e.printStackTrace(); 
   } 
  } 
   } }.start(); 
           
  1. 在傳遞給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(); 
           
  1. 總結

檢視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标記的變量可以被編譯器優化