#在千鋒“逆戰”學習第29天#多線程、Question12

總結

同步規則
注意:
只有在調用包含同步代碼塊的方法,或者同步方法時,才需要對象的鎖標記
如調用不包含同步代碼塊的方法,或普通方法時,則不需要鎖標記,可直接調用

已知JDK中線程安全的類:
StringBuffer
Vector
Hashtable
以上類中的公開方法,均爲synchronized修飾的同步方法

經典問題

死鎖
當一個線程擁有A對象鎖標記,並等待B對象鎖標記,同時第二個線程擁有B對象鎖標記,並等待A對象鎖標記時,產生死鎖。
一個對象可同時擁有多個對象的鎖標記,當線程阻塞時,不會釋放已經擁有的鎖標記,由此可能造成死鎖。

生產者、消費者
若干個生產者在生產產品,這些產品將提供給若干個消費者去消費,爲了使生產者和消費者能併發執行,在兩者之間設置一個能儲存多個產品的緩衝區,生產者將生產的產品放入緩衝區,消費者從緩衝區取走產品進行消費,顯然生產者和消費者之間必須保持同步,既不允許消費者到一個空緩衝區中取產品,也不允許生產者向一個滿的緩衝區放入產品。

線程通信

等待
public final void wait()
public final void wait(long timeout)
必須在對obj加鎖的同步代碼塊中。在一個線程中,調用obj.wait()時,此線程會釋放其擁有的所有鎖標記。同時此線程阻塞在o的等待隊列中,釋放鎖,進入等待隊列。

通知
public final void notify()
public final void notifyAll()
必須在對obj加鎖的代碼塊中,從obj的Wainting中釋放一個或全部線程,對自身沒有任何影響

高級多線程

線程池概念
現有問題
線程是寶貴的內存資源,單個線程約佔1MB空間,過多分配易造成內存溢出
頻繁的創建及銷燬進程會增加虛擬機回收頻率,資源開銷,造成程序性能下降
線程池
線程容器,可設定線程分配的容量上限
將預先創建的線程對象存入池中,並重複用線程池中的線程對象
避免頻繁的創建和銷燬
在這裏插入圖片描述
獲取線程池
Executor:線程池的頂級接口

ExecutorService:線程池接口,可通過submit(Runnable task)提交任務代碼

Executors工廠類:通過此類可以獲得一個線程池

通過newFixedThreadPool(int nThread)獲取固定數量的線程池。參數:指定線程池中線程的數量

通過newCachedThreadPool()獲得動態數量的線程池,如不夠創建新的,沒有上限

Callable接口
public interface Callable{
public V call() throws Exception;
}
JDK5加入,與Runnable接口類似,實現之後代表一個線程任務。
Callable具有泛型返回值、可以聲明異常

Future接口
概念:異步接收ExecutorService.submit()所返回的狀態結果,當中包含了call()的返回值

方法:V get()以阻塞形式等待Future中的異步處理結果(call()的返回值)

在這裏插入圖片描述
在這裏插入圖片描述

--------------------------------------------------------------------------------------作業分割線
8. (線程同步)有下面代碼

1) class MyThread extends Thread{
2) private String data;
3) public MyThread(String data){
4) this.data = data;
5) }
6) public void run(){
7) for(int i = 0; i<100; i++){
8) System.out.println(data);
9) }
10) }
11) }
12) public class TestMyThread{
13) public static void main(String args[]){
14) Thread t1 = new MyThread(“aaa”);
15) Thread t2 = new MyThread(“bbb”);
16) t1.start();
17) t2.start();
18) }
19) }

現希望能夠同步的輸出 aaa 和 bbb,即一次輸出 100 個 aaa 或 bbb,輸出這兩個字符串時沒有交互。
爲了達到上述目的,要對原代碼進行修改。以下哪些修改方式能夠得到想要的結果?
A. 把第 6 行改爲 public synchronized void run()
B. 把 run 方法中所有的內容都放在 synchronized(data)代碼塊中
C. 把 run 方法中所有的內容都放在 synchronized(System.out)代碼塊中

答:AC
B因爲會傳入不同的對象,不是對同一對象進行同步鎖,所以不行。

  1. (線程綜合)代碼改錯
class MyThread1 implements Runnable{
public void run() {
for(int i = 0; i<100; i++){
this.sleep((int)(Math.random()*1000));
System.out.println(“hello”);
} } }
class MyThread2 extends Thread{
public void run() throws Exception {
for(int i = 0; i<100; i++){
this.sleep((int)(Math.random()*1000));
System.out.println(“world”);
} } }
public class TestMyThread{
public static void main(String args[]){
Runnable t1 = new MyThread1();

Thread t2 = new MyThread2();
t1.start();
t2.start();
} }

答:
答:MyThread1裏面沒有sleep方法,需要用Thread.sleep直接調用,並加上try塊。
MyThread2裏面sleep方法加到try塊裏
t1引用類型應爲Thread 寫爲Thread t1 = new Thread(new MyThread1());

練習:繼承Runnable接口,使用兩個線程併發計算1到50,51到100的和,再進行彙總統計。
在這裏插入圖片描述

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