java3線程答案

22.JNInative是方法修飾符。Native方法是由另外一種語言(如c/c++,FORTRAN,彙編)實現的本地方法。

1)、繼承Thread類實現多線程

繼承Thread類的方法儘管被我列爲一種多線程實現方式,但Thread本質上也是實現了Runnable接口的一個實例,它代表一個線程的實例,並且,啓動線程的唯一方法就是通過Thread類的start()實例方法。start()方法是一個native方法,它將啓動一個新線程,並執行run()方法。這種方式實現多線程很簡單,通過自己的類直接extend Thread,並複寫run()方法,就可以啓動新線程並執行自己定義的run()方法。例如

  1. ublic class MyThread extends Thread {  
  2.   public void run() {  
  3.    System.out.println("MyThread.run()");  
  4.   }  
  5. }  
  1. MyThread myThread1 = new MyThread();  
  2. MyThread myThread2 = new MyThread();  
  3. myThread1.start();  
  4. myThread2.start();  
2)實現Runnable接口方式實現多線程

  1. public class MyThread extends OtherClass implements Runnable {  
  2.   public void run() {  
  3.    System.out.println("MyThread.run()");  
  4.   }  
  5. }  
爲了啓動MyThread,需要首先實例化一個Thread,並傳入自己的MyThread實例:
[java] view plain copy
  1. MyThread myThread = new MyThread();  
  2. Thread thread = new Thread(myThread);  
  3. thread.start();  
3)類似的,無返回值的任務必須Runnable接口,可返回值的任務必須實現Callable接口執行Callable任務後,可以獲取一個Future的對象,在該對象上調用get就可以獲取到Callable任務返回的Object了,再結合線程池接口ExecutorService就可以實現傳說中有返回結果的多線程了,ExecutoreService提供了submit()方法,傳遞一個Callable,或Runnable,返回Future。

23.線程的狀態轉換


(一). 等待阻塞運行(running)的線程執行o.wait()方法,JVM會把該線程放入等待隊列(waitting queue)中。由於notify()只是喚醒一個線程,但我們由不能確定具體喚醒的是哪一個線程,也許我們需要喚醒的線程不能夠被喚醒,因此在實際使用時,一般都用notifyAll()方法,喚醒有所線程)

(二). 同步阻塞運行(running)的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM會把該線程放入鎖池(lock pool)中。當線程剛進入可運行狀態(注意,還沒運行),發現將要調用的資源被synchroniza(同步),獲取不到鎖標記,將會立即進入鎖池狀態,

(三). 其他阻塞運行(running)的線程執行Thread.sleep(long ms)或t.join()方法,或者發出了I/O請求時,JVM會把該線程置爲阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入可運行(runnable)狀態。

線程同步方法:synchronize與wait-notify

synchronize與lock:自動與手動釋放鎖

sleep是線程類不會釋放鎖對象

wait是Object類方法會釋放鎖對象

24.如何停止一個線程

使用interrupt方法終止線程 

(1)線程處於阻塞狀態,如使用了sleep方

法。 

    (2)使用while(!isInterrupted())

{……}來判斷線程是否被中斷。 

    在第一種情況下使用interrupt方法,sleep

方法將拋出一個InterruptedException例外,

而在第二種情況下線程將直接退出



1 )處於運行狀態的線程停止:


線程需要通過設置停止變量的方式


2)處於可中斷等待線程的停止:線程調用了sleepwait方法,這些方法可拋出InterruptedException則可以通過調用Threadinterrupt方法讓等待方法拋出InterruptedException異常,然後在循環外截獲並處理異常


3) 處於IO阻塞狀態線程的停止:線程調用了IOread操作或者socketaccept操作,處於阻塞狀態。JavaInterruptableChanel接口提供了這樣的機制



25.如何保證線程安全

不要跨線程訪問共享變量


使共享變量是final類型的


將共享變量的操作加上同步


volatile聲明的數值類型變量進行運算, 往往是不安全的(volatile只能保證可見性,不能保證原子性

當一個線程請求獲得它自己佔有的鎖時(同一把鎖的嵌套使用), 我們稱該鎖爲可重入鎖

 提供了可重入鎖的java實現-ReentrantLock.  每個共享變量,都應該由一個唯一確定的鎖保護.創建與變量相同數目的ReentrantLock, 使他們負責每個變量的線程安全.

使用ThreadLocal變量確保線程封閉性(封閉線程往往是比較安全的, 但一定程度上會造成性能損耗)封閉對象的例子在實際使用過程中

在併發編程中, 需要容器支持的時候, 優先考慮使用jdk併發容器(ConcurrentHashMap, ConcurrentLinkedQueue, CopyOnWriteArrayList.但是他們支持的併發實現並不一定意味着操作的原子性,他們只是保證數據結構不被破壞

http://blog.csdn.net/fp196391196391/article

/details/39493761


26.Synchronized如何使用

1)方法聲明時使用,放在範圍操作符(public等)之後,返回類型聲明(void等)之前.這時,線程獲得的是成員鎖,即一次只能有一個線程進入該方法,其他線程要想在此時調用該方法,只能排隊等候,當前線程(就是在synchronized方法內部的線程)執行完該方法後,別的線程才能進入.

 public synchronized void synMethod() {
        
//方法體
      }

2)對某一代碼塊使用,synchronized後跟括號,括號裏是變量,這樣,一次只有一個線程進入該代碼塊.此時,線程獲得的是成員鎖

public int synMethod(int a1){
        synchronized(a1) 
{
          
//一次只能有一個線程進入
        }

      }

3)synchronized後面括號裏是一對象,此時,線程獲得的是對象鎖

public void run() {
    synchronized (
this{
      System.
out.println(Thread.currentThread().getName());
    }

4) synchronized後面括號裏是類,此時,線程獲得的是對象鎖

public ArrayWithLockOrder(int[] a)
  
{
    arr 
= a;
    synchronized(ArrayWithLockOrder.
class{//-----這裏
      num_locks++;             // 鎖數加 1。

      lock_order 
= num_locks;  // 爲此對象實例設置唯一的 lock_order。
    }



27.

lock和synchronized關鍵詞的區別

synchronized是在JVM層面上實現的,不但可以通過一些監控工具監控synchronized的鎖定,而且在代碼執行時出現異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過代碼實現的,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中
在資源競爭不是很激烈的情況下,Synchronized的性能要優於ReetrantLock,但是在資源競爭很激烈的情況下,Synchronized的性能會下降幾十倍,但是ReetrantLock的性能能維持常態;
28.sleep和wait的區別


這兩個方法來自不同的類分別是,sleep來


自Thread類,和wait來自Object類。


最主要sleep方法沒有釋放鎖,而wait方


法釋放了鎖,


使用範圍:wait,notify和notifyAll只能

在同步控制方法或者同步控制塊裏面使用,

而sleep可以在任何地方使用 


29.守護進程:


守護線程:守護線程則是用來服務用戶線程

的,如果沒有其他用戶線程在運行,那麼就

沒有可服務對象,也就沒有理由繼續下去。

setDaemon(boolean on)方法必須在線程

啓動之前調用,當線程正在運行時調用會產

生異常。


30.Java線程池技術及原理


    使用線程池的好處: 

    1.減少在創建和銷燬線程上所花的時間以及系統資源的開銷 
    2.如不使用線程池,有可能造成系統創建大量線程而導致消耗完系統內存以及”過度切換”。

   JDK自帶線程池總類

1)newFixedThreadPool創建一個指定工作線程數量的線程池。每當提交一個任務就創建一個工作線程,如果工作線程數量達到線程池初始的最大數,則將提交的任務存入到池隊列中。 

2)newCachedThreadPool創建一個可緩存的線程池。工作線程的創建數量幾乎沒有限制(其實也有限制的,數目爲Interger. MAX_VALUE

3)newSingleThreadExecutor創建一個單線程化的Executor,即只創建唯一的工作者線程來執行任務,如果這個線程異常結束,會有另一個取代它,保證順序執行(我覺得這點是它的特色)

4)newScheduleThreadPool創建一個定長的線程池,

31.java併發包concurrent及常用的類

http://www.cnblogs.com/vijozsoft/p/558562

0.html//集合

Java內存模型:


java內存模型中規定了所有的變量都存儲在主內存中,每條線程還有自己的工作內存(可以與前面將的處理器的高速緩存類比),線程的工作內存中保存了該線程使用到的變量到主內存副本拷貝,線程對變量的所有操作(讀取、賦值)都必須在工作內存中進行,而不能直接讀寫主內存中的變量。不同線程之間無法直接訪問對方工作內存中的變量,線程間變量值的傳遞均需要在主內存來完成,線程、主內存和工作內存的交互關係如下圖所示



volatile關鍵字

  • 可見性。對一個volatile變量的讀,總是能看到(任意線程)對這個volatile變量最後的寫入。

  • 原子性:對任意單個volatile變量的讀/寫具有原子性,

下面對volatile寫和volatile讀的內存語義做個總結:

  • 線程A寫一個volatile變量,實質上是線程A向接下來將要讀這個volatile變量的某個線程發出了(其對共享變量所在修改的)消息。

  • 線程B讀一個volatile變量,實質上是線程B接收了之前某個線程發出的(在寫這個volatile變量之前對共享變量所做修改的)消息。

  • 線程A寫一個volatile變量,隨後線程B讀這個volatile變量,這個過程實質上是線程A通過主內存向線程B發送消息。



1) ConcurrentHashMap

 ConcurrentHashMap是線程安全的HashMap的實現,默認構造同樣有initialCapacity和loadFactor屬性,不過還多了一個concurrencyLevel屬性,三屬性默認值分別爲16、0.75及16。其內部使用鎖分段技術,維持這鎖Segment的數組,在Segment數組中又存放着Entity[]數組,內部hash算法將數據較均勻分佈在不同鎖中。

oncurrentHashMap默認情況下采用將數據分爲16個段進行存儲,並且16個段分別持有各自不同的鎖Segment,鎖僅用於put和remove等改變集合對象的操作,基於volatile及HashEntry鏈表的不變性實現了讀取的不加鎖。這些方式使得ConcurrentHashMap能夠保持極好的併發支持,尤其是對於讀遠比插入和刪除頻繁的Map而言,而它採用的這些方法也可謂是對於Java內存模型、併發機制深刻掌握的體現。

ConcurrentLinkedQueue是一個基於鏈接節點的、無界的、線程安全的隊列




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章