同步機制以及執行緒組、執行緒池
一: 程序同步是程序之間直接的相互作用,是合作程序間有意識的行為,典型的例子是公共汽車上司機與售票員的合作。只有當售票員關門之後司機才能啟動車輛,只有司機停車之後售票員才能開車門。司機和售票員的行動需要一定的協調。同樣地,兩個程序之間有時也有這樣的依賴關係,因此我們也要有一定的同步機制保證它們的執行次序。
問題一:wait(),notify(),notifyAll() 這些方法為什麼會定義在Object類中呢?
答:這些方法好像就屬於執行緒的方法,但是Thread類中並沒有這些方法,多執行緒中同步鎖物件:任意的Java類這些方法都和鎖物件有關係,所以定義在Object類
答:對於sleep()方法,我們首先要知道該方法是屬於Thread類中的。
sleep()方法導致了程式暫停執行指定的時間,讓出cpu該其他執行緒,但是他的監控狀態依然保持者,當 指定的時間到了又會自動恢復執行狀態。在呼叫sleep()方法的過程中,執行緒不會釋放物件鎖。
而wait()方法,則是屬於Object類中的。 當呼叫wait()方法的時候,執行緒會放棄物件鎖,進入等待此 物件的等待鎖定池,只有針對此物件呼叫notify()方法後本執行緒才進入物件鎖定池準備
獲取物件鎖進入執行狀態。
問題三: 同步機制(同步程式碼塊/同步方法)此時出現了非執行緒安全問題,因為兩個執行緒同時訪問一個沒有同步 的方法,如果這兩個執行緒同時操作業務物件中的例項變數,就有可能出現非執行緒安全問題。
答:解決方案在開發中,使用synchronized(Lock鎖也可以)同步程式碼塊將多條語句對共享資料的操作包起來! 只需要在 public void run()前面加synchronized關鍵詞即可。
注:關於Lock物件和synchronized關鍵字的選擇:
a.最好兩個都不用,使用一種java.util.concurrent包提供的機制,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;
}
}