線程總結

 想走的遠,那麼你基礎一定要好。別以爲這些不是東西。未來能走多遠,要看基礎

1,兩種開啓線程方法:子類,Runnable接口。
                new Thread(){run(){...}}.start();
                new Thread(new Runnable(){run(){...}}).start();


2,定時器Timer,在新的線程裏面定時的去做任務(TimerTask接口),設定和運行
                new Timer().schedule(new TimerTask(){run(){...}}, time,times),第一個是要做的任務,用TimerTask封裝,第二個是要定的時間,第三個是第二次之後的定時時間。例如,第一次10秒,之後3秒做一次任務,有多少種調用方式,就自己看代碼了。

3,線程安全:同步,也就是一些代碼只能有一個線程進去,另外的線程想進去,必須等這個線程出來現。
synchronized(對象的鎖){},可以修飾代碼塊,方法,靜態方法
synchronized(this){要保護的代碼},這裏的鎖是this,其實可以是什麼都行的。在內存的位置是一樣的就可以同步了。
塊:鎖是什麼自己寫
方法:鎖是this
靜態方法:鎖是類,字節碼來的

4,線程通信和互斥:我們想在線程1 在工作的時候,線程2 不要去幹預,等線程一工作累了,就告訴線程2 ,線程2 來工作。
這樣我們就要用到中間類,new  成final  就可以通信了,之後又同步這個類的方法,只讓一個線程進。在這個類加一個判斷成員變量就簡單多了。通過中間類來完成通信。不是線程管。

5,綁定線程數據:new  一個Map,這樣就可以用線程對象多key  ,那麼拿值的時候就會不同了,這就是綁定數據。線程結束就刪除對應的一條數據就好。 

6,綁定線程數據:ThreadLocal,這個對象相當一個map,set  值就會和線程關聯了,只管加入數據。綁定那個數據ThreadLocal  管理。如果想綁定多個數據,就封裝一下。要保證ThreadLocal  是唯一的。

7,多個線程訪問同一個共享數據,原理:保證數據對象是一個。
  • 將共享數據和操作方法封裝在一個對象中,然後將這個對象傳遞個Runnable  對象(線程要運行的代碼就在這個對象裏面),這樣就容易實現數據的互斥和通信。最好就加上同步。
  • 利用內部類訪問外部成員:把要處理的數據當作類的屬性,處理方法封裝好,記得同步,把Runnable  繼承成內部類,那麼run  方法就可以訪問了。
 ------以上是java1.4 以前版本的寫法,下面是1.5 的 -----


8,線程池ThreadPool:這個人,是管理線程去做任務的,做任務的中介吧,如果人家有任務(Runnable )就給這個線程池,給完就可以回去了,中介是有工廠或人力的(線程Thread),看看誰有空,有空就叫去做任務,如果全部都在忙,那麼這些任務就會在隊列裏面排隊,是異步處理的。做網站服務器類似的就會用到。
  • ThreadPool  線程池
  • ExecutorService threadPool = Executors.newFixedThreadPool(3);  固定的工人,就是固定的線程
  • ExecutorService threadPool = Executors.newCachedThreadPool();  有緩衝的,有多少任務就請多少工人
  • ExecutorService threadPool = Executors.newSingleThreadExecutor();  單個,解決線程死掉怎麼救活
  • 任務 Runnable
  • threadPool.execute(new Runnable(){要做的任務});  這個方法在主線程調用,加入任務的。
  • 工具類  Executors

9,線程返回結果Future:當一個線程結束之後就會返回一個結果給我們。
  • 在線程池用submit()提交任務,這個時候任務是Callable  ,類似Runnable,運行函數爲 call()  有返回結果的。
  • Future future =threadPool.submit(new Callable() {call(){...}};
  • 之後再調用 future.get()拿到返回結果的。但不知道什麼時候有返回結果,感覺沒有什麼用咯,還不如自己做任務,你幫我做任務,還要我看着。
10,提交多個任務CompletionService  :new 的時候要傳進線程池,也是用submit()提交任務。用completion.task().get();拿到返回的結果,一次拿一個,


11,java5中的鎖Lock : 就是同步,進入一段代碼的時候,鎖上,在出來的時候,開鎖,這樣就不怕的被打斷了。
  • Lock lock = new ReentrantLock();  //Lock  是接口,要new  其子類,Ctrl + T 一下就知道了。
  • lock.lock();  //上鎖
  • try{......}finally{lock.unlock();} //開鎖,要try/finally

12,讀寫鎖ReadWriteLock : 可以上讀或寫的鎖,讀與讀不互斥,讀與寫互斥,寫與寫互斥。
  • rw.readLock().lock();
  • rw.readLock().unlock();
  • rw.writeLock().lock();
  • rw.writeLock().unlock();
13,線程交換工作:就是你一下,我一下的工作,這個思想是怎麼樣呢。不是自己工作就wait(),自己做完了就notify(),叫醒別人。
  • 在通信的中,共享的數據封裝在相對線程是外部的,有了一個唯一的數據對象data。
  • data有兩個方法,分別給不同的線程調用m1()和m2();這兩個方法會加Lock的。
  • 一開始是線程一調用m1(),在線程機制中,每一個分配的時間是由CPU控制的,不能設置,那麼現在是線程一工作,就要用狀態變量標識bShouldSub,
  • 當線程一工作完了,就喚醒線程二,但本應該到線程二工作了,但CPU還不急讓線程二工作,時間還是給了線程一,這個時候就應該讓線程一wait(),這樣線程二就可以工作了。
  • 重複上面的過程,就是可以,你一下,我一下的工作了。

  • 完成這個,完成上面的通信,是在鎖住的時候通信的,就是Lock裏面的通信Condition,Lock.Condition
  • 生成鎖,lock = new ReentrantLock();
  • 拿到這個鎖的通信,Condition condition =   lock. newCondition();  
  • 用condition.await()  代替  this.wait();
  • 用condition.signal(); 代替  this.notity();    , 同一個signal(),  只能叫醒用同一個對象await() 的對象。
  • 這樣就可以了。稱爲:多個Condition通信,可以很多個Condition

  • 從兩個封裝中更加能體現面向對象的思想。用Condition可以實現諸塞隊列。
14,燈的互斥Semaphore:信號 vt. 用信號聯絡  vi. 發信號,這個人是管理工作的人數,只有有燈的線程才能去工作,不然就wait()
  • sp.acquire();  獲得燈,如果沒有燈就等,等,可以做排隊用。有多少 隊 ,就有多少燈
  • sp.release();  做完任務就還燈。

15,線程集合一起行動:CyclicBarrier,在new  的時候就會告訴這個人,我們又多少個線程要去工作,如果線程調用這個類的await()  方法,說明到達了集合地點,那麼要等夠一開始設置的線程數量才能一起出發,這個等待是自己動開始的,只要人數夠了,就可以行動。
  • final  CyclicBarrier cb = new CyclicBarrier(3);
  • cb.await();// 一定要等夠線程調用這個方法才能走下去。
16,計數器:CountDownLatch , 給我看清楚了,這個是計數器,不是計時器,是用來算數字的,一開始設置有多少個數,一次減去1 ,直到零,如果有線程用這個對象來await(),  那麼就可以開始往下走。同一對象原則。互動對象原則
  • 應用1 :設置計數爲1 ,有一個準備時間,到時間減1 開始行動,就像起跑線上的。
  • 應用2 :設置計數爲總人數 n,每一個人做完工作就減1 ,當全部人做完工作,剛好減爲 0 ,就可以去統計什麼的,就像都跑到了終點。
  • final CountDownLatch cdOrder = new CountDownLatch(1);
  • final CountDownLatch cdAnswer = new CountDownLatch(3);
  • cdOrder.await();
  • cdOrder.countDown();
  • 一對多,多對一
17,線程交換數據:Exchanger,連個線程交換數據,誰先到交換地點誰就等一下,調用了一個方法exchange(data), 就是到達了,當兩個人都到了的時候就交換,之後就向下走了。可以換不同的數據
  • final Exchanger exchanger = new Exchanger();
  • Ex data2 = (Ex)exchanger.exchange(data1);
18,阻塞隊列:BlockkingQueue,想知道怎麼用就看API去,可以和線程池結合使用。
  • 放滿之後就在等待,等有人拿走了才能放進去。

19,併發集合: ConcurrentSkipListMap等等,要用就是查,我這裏只是講幾個。
  • 之前的集合對線程是不安全的。讀的時候就不要寫,寫的時候就不要讀。就想lock  一樣,有異常這些東西的。只是原本Collection  的毛病。
  • CopyOnWriteArrayList  這個類在寫的時候會Copy  一份,就不會有事,
20,同步隊列:SynchronousQueue,也是一個阻塞隊列,這個隊列是,當有人來讀的時候才插入數據。如果有多個人來讀數據,就插進去,看誰搶的快,誰就拿唄。

問題:可以不可以,主線程調用線程1 下載數據,主線程在做自己的事情,當線程1 下載完數據之後主線程就拿到下載後的數據輸出。就是沒有等待的時間。以上講的都是異步線程同步通信的。




線程要做的東西:
  1. 做任務:
  2. 線程池最好,把任務一丟就行了。任務是Runnable
  3. 阻塞隊列也行,自己new  Thread,任務是什麼都行,如果想線程多次拿隊列的東西,就 while(true){...}
  4. 排隊消費:有線程,隊列,燈
  5. 只有一盞燈,只有拿到燈的才能消費。
  6. 用同步隊列,只有有人來拿數據才插入數據
  7. 用new  產生線程,用來消費
注意:

  1. 線程池的工作是做任務,只管做完,在做完的時候也可以返回結果,但這樣的結果沒有什麼用,和通信有很大的差別,通信可以一做一下,我做一下,但線程池,你給任務,我就一下子去做完。

看完幫忙評論一下,一起進步嘛。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章