1. 程式人生 > >同步機制以及執行緒組、執行緒池

同步機制以及執行緒組、執行緒池

         一: 程序同步是程序之間直接的相互作用,是合作程序間有意識的行為,典型的例子是公共汽車上司機與售票員的合作。只有當售票員關門之後司機才能啟動車輛,只有司機停車之後售票員才能開車門。司機和售票員的行動需要一定的協調。同樣地,兩個程序之間有時也有這樣的依賴關係,因此我們也要有一定的同步機制保證它們的執行次序。 

            問題一:wait(),notify(),notifyAll() 這些方法為什麼會定義在Object類中呢?

             答:這些方法好像就屬於執行緒的方法,但是Thread類中並沒有這些方法,多執行緒中同步鎖物件:任意的Java類

 這些方法都和鎖物件有關係,所以定義在Object類

           問題二:wait()和sleep(long times) 的區別?

 答:對於sleep()方法,我們首先要知道該方法是屬於Thread類中的

         sleep()方法導致了程式暫停執行指定的時間,讓出cpu該其他執行緒,但是他的監控狀態依然保持者,當      指定的時間到了又會自動恢復執行狀態。在呼叫sleep()方法的過程中,執行緒不會釋放物件鎖。

          而wait()方法,則是屬於Object類中的。 當呼叫wait()方法的時候,執行緒會放棄物件鎖,進入等待此      物件的等待鎖定池,只有針對此物件呼叫notify()方法後本執行緒才進入物件鎖定池準備

     獲取物件鎖進入執行狀態。


 問題三:  同步機制(同步程式碼塊/同步方法)此時出現了非執行緒安全問題,因為兩個執行緒同時訪問一個沒有同步         的方法,如果這兩個執行緒同時操作業務物件中的例項變數,就有可能出現非執行緒安全問題。

        答:解決方案在開發中,使用synchronized(Lock鎖也可以)同步程式碼塊將多條語句對共享資料的操作包起來!  只需要在       public void run()前面加synchronized關鍵詞即可。

:關於Lock物件和synchronized關鍵字的選擇:

        a.最好兩個都不用,使用一種java.util.concurrent包提供的機制, 
            能夠幫助使用者處理所有與鎖相關的程式碼。         b.如果synchronized關鍵字能滿足使用者的需求,就用synchronized,因為它能簡化程式碼         c.如果需要更高階的功能,就用ReentrantLock類,此時要注意及時釋放鎖,         否則會出現死鎖,通常在finally程式碼釋放鎖 。   ReenreantLock類的常用方法有:
          ReentrantLock() : 建立一個ReentrantLock例項 
          lock() : 獲得鎖 
          unlock() : 釋放鎖 

二: 執行緒組:程組表示一個執行緒的集合。此外,執行緒組也可以包含其他執行緒組。

執行緒組存在的意義,首要原因是安全。    java預設建立的執行緒都是屬於系統執行緒組,而同一個執行緒組的執行緒是可以相互修改對方的資料的。    但如果在不同的執行緒組中,那麼就不能“跨執行緒組”修改資料,可以從一定程度上保證資料安全. 

   【示例程式】

public static void main(String[] args) {

//獲取執行緒組的名稱

           //method1();

//如何給多個執行緒設定一個執行緒組名稱呢?
method2();
}


private static void method2() {
//public ThreadGroup(String name)構造一個新執行緒組
ThreadGroup tg = new ThreadGroup("main-新的執行緒組") ;

MyThread my = new MyThread() ;

//Thread(ThreadGroup group, Runnable target, String name) 
Thread t1 = new Thread(tg, my, "執行緒1") ;
Thread t2 = new Thread(tg, my, "執行緒2") ;

//直接獲取執行緒組名稱
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
}


private static void method1() {
MyThread my = new MyThread() ;

//建立執行緒類物件

Thread t1 = new Thread(my, "執行緒1") ;
Thread t2 = new Thread(my, "執行緒2") ;

//public final ThreadGroup getThreadGroup()返回該執行緒所屬的執行緒組
ThreadGroup tg1 = t1.getThreadGroup() ;
ThreadGroup tg2 = t2.getThreadGroup() ;

//public final String getName():返回執行緒組的名稱
System.out.println(tg1.getName()); //main
System.out.println(tg2.getName());//main

//所有的執行緒它預設的執行緒組名稱:main(主執行緒)
System.out.println(Thread.currentThread().getThreadGroup().getName());//main
}
}

 

三: 執行緒池(某個執行緒執行完畢,反覆利用執行緒物件

        執行緒池:多個執行緒執行完畢,它會重新回到執行緒池中,等待被利用,不會變成垃圾!

執行緒池存在的意義,首要作用是效率。    執行緒的建立和結束都需要耗費一定的系統時間(特別是建立),不停建立和刪除執行緒會浪費大量的時間。所     以,在創建出一條執行緒並使其在執行任務後不結束,而是使其進入休眠狀態,在需要用時再喚醒,那麼 就     可以節省一定的時間。    如果這樣的執行緒比較多,那麼就可以使用執行緒池來進行管理。保證效率。
 和執行緒池有關的類
       類 Executors: 一種工廠類
       方法:
 和執行緒池的建立有關係
 public static ExecutorService newFixedThreadPool(int nThreads)
 建立一個可重用固定執行緒數的執行緒池
 
        ExecutorService:可以執行非同步任務
建立一個執行緒池,執行介面中的方法
 提交:Future<?> submit(Runnable task)
 <T> Future<T> submit(Callable<T> task)提交一個返回值的任務用於執行,返回一個表示任務的                         未決結果的 Future
                       Future:介面(Future 表示非同步計算的結果)

 執行緒池呼叫完畢可以關閉的

 void shutdown():關閉之前,會提交剛才的任務

【示例程式】:主程式分別計算每個執行緒的求和! 

 

                package org.westos_15;
                import java.util.concurrent.ExecutionException;
                import java.util.concurrent.ExecutorService;
                import java.util.concurrent.Executors;
                import java.util.concurrent.Future;

                public class ExecutorsTest {

public static void main(String[] args) throws InterruptedException,ExecutionException {

//建立執行緒池物件
ExecutorService pool = Executors.newFixedThreadPool(2) ;

//提交任務
Future<Integer> f1 = pool.submit(new MyCallable(100)) ;
Future<Integer> f2 = pool.submit(new MyCallable(200)) ;

//V get():獲取結果
Integer i1 = f1.get() ;
Integer i2 = f2.get() ;

System.out.println(i1);
System.out.println(i2);

//關閉執行緒池
pool.shutdown();
}

}

子程式

            package org.westos_15;
            import java.util.concurrent.Callable;
            public class MyCallable implements Callable<Integer> {

//定義個變數
private int number ;


public MyCallable(int number) {
this.number = number;
}

@Override
public Integer call() throws Exception {
//定義最終結果變數
int sum = 0 ;
for(int x =1 ; x <=number ; x ++) {
sum +=x ;
}
return sum;
}
}

 四:執行緒組和執行緒池共有的特點:    1,都是管理一定數量的執行緒    2,都可以對執行緒進行控制---包括休眠,喚醒,結束,建立,中斷(暫停)--但並不一定包含全部這些操作。