開始第二遍學習java了,發現有好多的知識點在之前學習的時候是不了解的。在java多線程的板塊中,學到了除了繼承Thread 實現runnable接口以外 還學到了第三種的基於線程池的實現callable接口的線程方式。感覺java真實博大精深。對java線程的筆記總結:
1:多線程
(1)多線程:一個應用程序有多條執行路徑 進程:正在執行的應用程序 線程:進程的執行單元,執行路徑 單線程:一個應用程序只有一條執行路徑 多線程:一個應用程序有多條執行路徑
多進程的意義?
提高CPU的使用率
多線程的意義?
提高應用程序的使用率
(2)Java程序的運行原理及JVM的啟動是多線程的嗎?
A:Java命令去啟動JVM,JVM會啟動一個進程,該進程會啟動一個主線程。
B:JVM的啟動是多線程的,因為它最低有兩個線程啟動了,主線程和垃圾回收線程。
* 兩種方式的比較
B:獲取和設置線程優先級
a:默認是5
b:范圍是1-10
線程睡眠毫秒數
join:等待線程終止,等待線程執行完畢後其它的線程才可以運行
一定程度上讓多個線程的執行和諧,不靠譜
public final void stop() 讓線程停止,已過時
public void interrupt() 終止線程,並且拋出InterruptedException異常,並會執行後續的代碼
創建線程對象的過程<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPGg0PkI6vs3Q9zwvaDQ+CjxwPgrT0Na00NC1xMz1vP66zdfKJiMyNjY4NDujrMO709DWtNDQyKg8L3A+CjxoND5jOtTL0NA8L2g0Pgo8cD4K09DUy9DQtcTXyiYjMjY2ODQ7o6zT0Na00NDIqDwvcD4KPGg0PkQ61+jI+zwvaDQ+CjxwPgrDu9PQ1rTQ0NfKJiMyNjY4NDujrMO709DWtNDQyKg8L3A+CjxoND5FOsvAzfY8L2g0Pgo8cD4Kz9+zzLbUz/Ox5LPJwKy7+KOstci0/bG7u9jK1TwvcD4KPHByZSBjbGFzcz0="brush:java;">(7)電影院賣票程序的實現
A:繼承Thread類
B:實現Runnable接口
(8)電影院賣票程序出問題
A:為了更符合真實的場景,加入了休眠100毫秒。
B:賣票問題
a:同票多次
b:負數票
(9)多線程安全問題的原因(也是我們以後判斷一個程序是否有線程安全問題的依據)
A:是否有多線程環境
B:是否有共享數據
C:是否有多條語句操作共享數據
synchronized(對象) {
需要被同步的代碼;
}
這裡的鎖對象可以是任意對象。
把同步加在方法上。
這裡的鎖對象是this
把同步加在方法上。
這裡的鎖對象是當前類的字節碼文件對象(反射再講字節碼文件對象)
- A:StringBuffer
- B:Vector
- C:Hashtable
- D:如何把一個線程不安全的集合類變成一個線程安全的集合類用Collections工具類的方法即可。
// 定義鎖對象
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
// 加鎖
lock.lock();
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "張票");
}
} finally {
// 釋放鎖
lock.unlock();
}
}
}
- 是指兩個或者兩個以上的線程在執行的過程中,因爭奪資源產一種互相等待現象
- 同步代碼塊的嵌套案例
@Override
public void run() {
// 死鎖代碼
if (flag) {
// 同步嵌套
synchronized (MyLock.objA) {
System.out.println("if obja");
synchronized (MyLock.objB) {
System.out.println("if objb");
}
}
} else {
synchronized (MyLock.objB) {
System.out.println("else objb");
synchronized (MyLock.objA) {
System.out.println("else obja");
}
}
}
}
以學生作為資源來實現的
資源類:Student
設置數據類:SetThread(生產者)
獲取數據類:GetThread(消費者)
測試類:StudentDemo
代碼:
A:最基本的版本,只有一個數據。
B:改進版本,給出了不同的數據,並加入了同步機制
C:等待喚醒機制改進該程序,讓數據能夠實現依次的出現
wait() 線程等待後立即釋放所持有的鎖,被喚醒後在等待的位置繼續執行
notify() 喚醒並不代表立馬可以執行 線程會轉為就緒狀態 等待下一次執行
notifyAll() (多生產多消費)
Thread(ThreadGroupgroup, Runnabletarget, Stringname)
新建線程組代碼:
// ThreadGroup(String name)
ThreadGroup tg = new ThreadGroup("這是一個新的組");
MyRunnable my = new MyRunnable();
// Thread(ThreadGroup group, Runnable target, String name)
Thread t1 = new Thread(tg, my, "林青霞");
Thread t2 = new Thread(tg, my, "劉意");
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
//通過組名稱設置後台線程,表示該組的線程都是後台線程
tg.setDaemon(true);
程序啟動一個新線程成本是比較高的,因為它涉及到要與操作系統進行交互。而使用線程池可以很好的提高性能,尤其是當程序中要創建大量生存期很短的線程時,更應該考慮使用線程池。
public static ExecutorService newCachedThreadPool()
創建一個具有緩存功能的線程池
緩存:百度浏覽過的信息再次訪問
public static ExecutorService newFixedThreadPool(int nThreads)
創建一個可重用的,具有固定線程數的線程池
public static ExecutorService newSingleThreadExecutor()
創建一個只有單線程的線程池,相當於上個方法的參數是1
protected void shutdown()
順序關閉線程池中的線程 這些方法的返回值是ExecutorService對象,該對象表示一個線程池,可以執行Runnable對象或者Callable對象代表的線程。它提供了如下方法
Future> submit(Runnable task)
Futuresubmit(Callabletask)
實現Callable接口 步驟和剛才演示線程池執行Runnable對象的差不多。 但是還可以更好玩一些,求和案例演示 好處: 可以有返回值 可以拋出異常 弊端: 代碼比較復雜,所以一般不用
new Thread(){代碼…}.start(); New Thread(new Runnable(){代碼…}).start();
定時器是一個應用十分廣泛的線程工具,可用於調度多個定時任務以後台線程的方式執行。在Java中,可以通過Timer和TimerTask類來實現定義調度的功能
Timer 一種工具,線程用其安排以後在後台線程中執行的任務。可安排任務執行一次,或者定期重復執行。
public Timer()
public void schedule(TimerTasktask, longdelay)
public void schedule(TimerTask task,long delay,long period)
* TimerTask 任務類用於為Timer指定任務 public abstract void run()
public boolean cancel()
* 開發中
Quartz是一個完全由java編寫的開源調度框架。線程的生命周期轉換圖: