一、基本概念
1、併發與並行:
1)併發:多個任務交替執行。
2)並行:多個任務同時執行。如果系統只有一個CPU,那真實環境中不可能是真實並行,因爲一個CPU一次只能執行一個指令。多核CPU有可能出現並行。
2、臨界區:
一種公共資源或共享數據,每一次只能有一個線程使用它。一旦臨界區資源被佔用,其他線程要想使用這個資源,就必須等待。
3、阻塞(Blocking)和 非阻塞(Non-Blocking):
阻塞:用來形容多線程間的相互影響。一個線程佔用了臨界區,其他需要使用這個臨界區的線程就必須等待,等待會導致線程掛起,這種情況就是阻塞。
非阻塞:沒有一個線程可以防礙其它線程執行。
4、死鎖(DeadLock)、飢餓(Starvation)和活鎖(LiveLock):
死鎖: 各線程彼此阻塞。
飢餓:某個或多個線程由於某種原因(線程優先級太低,或某個線程一直佔用資源)無法獲得需要的資源,導致一直無法執行。
活鎖:兩個線程相互謙讓資源,導致沒有一個線程可以同時拿到所有資源而正常執行。
5、併發級別:
根據控制併發的策略,可以發併發級別分爲: 阻塞、無飢餓、無障礙、無鎖、無等待。
6、多線程的原子性、可見性、有序性:
a、 原子性( Atomicity ):指一個操作是不可中斷的。即使是在多個線程一起執行的時候,一個操作一旦開始,就不會被其他線程干擾。
如: 對於32位系統,Long (64位)型數據的讀寫不是原子性的,
b、可見性:當一個線程修改了某一個共享變量的值,其他線程是否能夠立即知道這個修改。
如: 多核CPU中,CPU1 將變量 t 緩存在Cache或寄存器, 如果CPU2上的某線程修改了t 的值,則CPU1 不會知道,這就是可見性的問題。
可見性問題有多種情況: 緩存優化,硬件優化,指令重排,編輯器優化。
c、有序性:指令重排後,代碼執行順序會變化。
7、線程中斷的三種方法:
1) Thread.interrupt(); // 中斷線程
實例方法,通知目標線程中斷,即設置中斷標誌位。中斷標誌位表示當前線程已經被中斷了。
2) Thread.isInterrupted(); // 判斷是否被中斷
實例方法,判斷當前線程是否有被中斷(通過檢查中斷標誌位)。
3) Thread.interrupted(); // 判斷是否被中斷,並清除當前中斷狀態。
也用來判斷當前線程的中斷狀態,但同時會清除當前線程的中斷標識位狀態。
8、Thread.sleep()方法:
當線程在 sleep()休眠時,如果被中斷,則會拋出InterruptException中斷異常
該異常不是運行時異常,程序必須捕獲並處理它。
9、Object.wait() 方法:
當在一個對象實例上調用 wait()方法後,當前線程就會在這個對象上等待,直到其它線程調用了obj.notify()方法爲止。
obj對象成爲多個線程之間的通信手段。
Object.wait()方法必須包含在對應的 synchronized語句中。
執行前需要獲得目標對象的監視器 - 用synchronized 語句
wait() 和 sleep()方法的區別:
1)、相同點: 都可以讓線程等待,
2)、不同點: wati 可以被喚醒,會釋放目標對象的鎖,slee()方法不會釋放任何資源。
10、Object.notify()方法:隨機喚醒(不公平)等待的線程。
Object.notifyAll()方法:喚醒全部等待隊列中的線程。
執行前需要獲得目標對象的監視器
11、suspend( 掛起)和 resume (繼續執行)線程:
這是兩個相反的操作,已經不建議使用。
因爲: suspend()在掛起線程時,不釋放任何的鎖資源,直至對應的線程執行了resume()操作。
但如果 resume()操作先與 suspend()執行,則被掛起的線程在很難有機會被繼續執行。
嚴重時它佔用的鎖不被釋放,會導致整個系統工作不正常。
12、Join (等待線程結束) 和 yield ( 謙讓 ) 方法:
Join 方法有兩個:
a、 public final void join(): 無限等待,一直阻塞當前線程,直到目標線程執行完畢。
b、 public final synchronized void join( long millis ):給定一個最大等待時間,如超過
等待時間目標線程還在執行,當前線程會不再等待而繼續往下執行。
join()的核心代碼是 wait(0);
注:不要在應用程序中,在Thread對象實例上使用類似 wait()或 notify()等方法,
因爲這很可能會影響系統API的工作,或者被系統API所影響。(爲什麼? 沒有理解)
yield()方法定義: public static native void yield();
靜態方法,一旦執行,它會使當前線程讓出CPU。但後續還會進行CPU資源的爭奪。
如果一個線程不太重要或者優先級低,可以在適當的時候調用 Thread.yield().
13、Java內存模型:原子性、有序性、可見性。
14、volatile: 當用該關鍵詞聲明變量後,虛擬機會特別小心地處理,保證該變量的可見性。
但 volatile 不能代替鎖,也無法保證一些複合操作的原子性。
15、線程組:
ThreadGroup tg = new ThreadGroup("TGroup");
Thread t1 = new Thread(tg, new ThreadGroupName(), "T1");
Thread t2 = new Thread(tg, new ThreadGroupName(), "T2");
tg.activeCount()
tg.list();
16、守護線程( Daemon),與之對應的是用戶線程。
Thread t = new DaemonT();
t.setDaemon(true); //必須在 start()方法前設置。
t.start();
17、線程優先級:
java中,線程優先級從1到10。
高優先級的線程競爭資源時會更有優勢,但並不絕對。
18、線程安全的概念:
1)、synchronized 的基本用法:
a、指定加鎖對象:對給定對象加鎖,進入同步代碼前要獲得給定對象的鎖。
如: Object instance = new Object();
synchronized( instance )
{
...
}
main()
{
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start(); t2.start();
....
}
b、直接作用於實例方法:相當於對當前實例加鎖,進入同步代碼前要獲得當前實例的鎖。
如: publicsynchronized void increase()
{
...
}
main()
{
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start(); t2.start();
....
}
c、直接作用於靜態方法:相當於對當前類加鎖,進入同步代碼前要獲得當前類的鎖。
如:public staticsynchronized void increase()
{...}
main()
{
Thread t1 = new Thread(new StaticSyncInstatnce());
Thread t2 = new Thread(newStaticSyncInstatnce());
t1.start(); t2.start();
....
}
問題: 這三種用法是鎖的粒度範圍不同?a和b 有什麼區別?
二、線程池
1、工作方式:
有一個隊列,任務被提交到這個隊列中(也可有多個隊列)。一定數量的線程會從該隊列中取任務,
然後執行。執行完任務後,線程會從任務隊列中取下一個任務並執行,如果沒有任務要執行,則等待。
2、線程池有最小線程數和最大線程數,池中有最小數目的線程隨時待命,等待任務指派給他們。
最小線程數也叫核心池大小。
最大線程數是一個限流閥,防止一次執行太多線程。最大線程數的大小取決於負載特性以及底層硬件。
最優線程數還與每個任務的阻塞頻率有關。
3、線程池Executor框架:
ThreadPoolExecutor
Executors 爲線程池工廠,包含如下構造線程池的方法:
public staticExecutorServicenewFixedThreadPool() :
返回一個固定線程數量的線程池。
public staticExecutorService newSingleThreadExecutor:
返回只有一個線程的線程池。
public static ExecutorService newCachedThreadPool
返回一個可根據實際情況調整線程數量的線程池。線程池的線程數量不固定。
public staticScheduledExecutorServicenewSingleThreadScheduledExecutor
返回一個 ScheduledExecutorService 對象,線程池大小爲一。
ScheduledExecutorService接口在ExecutorService 接口只上擴展了在給定時間執行某任務的功能。
如在某個固定時間執行某任務的功能,如在某個固定的延遲之後執行,或者週期性的執行某個任務。
public staticScheduledExecutorService newScheduledThreadPool
該方法也返回一個ScheduledExecutorService對象,但該線程可以指定線程數量。
public staticExecutorService unconfigurableExecutorService
public static ScheduledExecutorService unconfigurableScheduledExecutorService
20、JDK 併發容器:
CuncurrentHashMap:
CopyOnWriteArrayList:
ConcurrentLinkedQueue:
BlockingQueue:
ConcurrentSkipListMap:
三、Java線程調試工具
1、jps - 顯示當前系統中所有的java 進程。
2、jstack 打印給定 Java 進程的內部線程及堆棧。
3、javap [不帶class後綴的類名]- 反編譯java 代碼
問題
1、ActomicLong 類?
2、JUC(包括重入鎖(Lock)、線程池/連接池(commom-pool)、Timer、Future模式、AQS、CAS等)
3、代理,反射