要了解"線程",必須先了解一下"進程":
什麼是進程:
1.對於"操作系統"而言,每個獨立運行的程序就是獨立的"進程";
2."操作系統"會分別針對每個"進程"分配一塊獨立的內存空間;
--什麼是多進程:
1."操作系統"可以同時維護多個"應用程序"的執行。
2.每個應用程序都交由操作系統管理,在某個時間點上,會有一個應用程序被操作系統分配給CPU去執行,執行一會後,會被操作系統
終止執行,並交由另一個"應用程序"繼續執行。由於轉換非常快,CPU的運算速度也非常快,這就讓我們感覺好像是多個應用程序在
同時執行一樣。
3.多進程的意義:
1).方便了我們用戶的使用。我們可以同時啓動多個程序,一邊聽歌,一邊上網,一邊下載;
2).充分的利用CPU資源;
什麼是線程:
1.線程是由一個"進程"的內部啓動的,可以脫離於"主進程"而獨立運行的一塊代碼;
2.一個線程一旦啓動,將和"主進程"並行運行,一起面對操作系統,搶佔系統資源;
3.一個"進程"可以啓動多個"線程";
--什麼是多線程:
1.一個進程可以同時啓動多個線程去單獨運行;這個程序就是一個多線程程序;
2.多線程的意義:
1).可以使我們的應用程序"同時"運行多個非常複雜的代碼;
2).使我們的程序不用等待那些代碼的執行完畢,就可以繼續獲得執行;
3).充分的利用了CPU的資源;
什麼是"並行"和"併發":
1."並行"是指邏輯上一起在執行,它強調的是在"同一段時間內"一起運行的程序;
2."併發"是指物理上的搶佔同一資源。它強調的是在"同一時刻時"一起搶佔系統的某個共享資源;
二, 實現線程的:
方式一
實現步驟:
1.自定義一個線程類,要繼承自Thread;
2.重寫Thread中的run()方法;將要在線程中執行的代碼寫到這裏;
3.啓動線程:
1).實例化一個我們自定義的線程類;
2).調用它的start()方法;啓動線程;
public class Demo {
02. public static void main(String[] args) {
03. MyThread t1 = new MyThread();
04. MyThread t2 = new MyThread();
05.
06. // t1.run();//相當於普通的方法調用,不是啓動一個線程
07. // t2.run();//相當於普通的方法調用,不是啓動一個線程
08.
09. t1.start();
10. t2.start();
11.
12. for(int i = 0;i < 100;i++){
13. System.out.println("主進程 i = " + i);
14. }
15.
16. //嘗試再次啓動t1
17. // t1.start();//運行時異常。不能多次調用start(),否則拋出異常:java.lang.IllegalThreadStateException
18. }
19.}
注意:
1.一個線程類,可以實例化多個對象,並分別啓動。也就意味着多個線程同時運行;
2.一個線程對象,只能調用一次start,不能重複調用。否則拋出異常:java.lang.IllegalThreadStateException
3.只用調用start()纔是啓動線程。run()方法內的代碼會以一個線程的方式去運行;
一.線程實現方式:
1.繼承Thread類;
2.實現Runnable接口;
二.設置獲取線程的名稱:
getName()和setName(String name);
三.設置獲取線程的優先級:
getPriority()和setPriority(int n);
線程的優先級範圍:1--10(從低到高)
四.線程的休眠:sleep(long m):休眠到指定的m毫秒後,將自動醒來;
加入:join();
禮讓:yield():退回到"就緒狀態",可能會被操作系統重新分配;
守護:setDaemon(boolean on):on爲true,守護線程。主進程結束,守護線程也結束,但不會立即結束,會有一個小緩衝;
中斷:stop()(過時了)
interrupt():線程一定要處於:Object-->wait();Thread-->sleep();Thread--join()三種狀態之一時,才能觸發此異常;
五.解決併發性問題:
1.使用關鍵字:synchronized
2.synchronized可以修飾一個代碼塊:同步代碼塊
synchronized可以修飾一個方法:同步方法
3.靜態的方法可以被synchronized修飾。
靜態的方法內部也可以包含synchronized的代碼塊,但一般鎖定是某個類的class對象。
一.JDK5的Lock鎖:
Lock lock = ....;
lock.lock();
try{
//需要同步的代碼
}finally{
lock.unlock();
}
二.死鎖的現象:
見圖
三.生產和消費者問題:
1.單生產和單消費;
2.在共享資源中:
1).wait():讓訪問的線程等待(釋放鎖)
2).notify()和notifyAll():喚醒;
四.線程組:
1.任何的線程都有一個默認的線程組;
2.可以自行指定線程組:
1).實例化一個線程組;
2).通過Thread的構造方法去指定線程組;
3.可以統一對線程組內的所有線程執行統一操作;
五.線程池:JDK5後出現:
1.Executors類的
public static ExecutorService newCachedThreadPool()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()
2.調用ExecutorService的:
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
六.JDK5的多線程的實現方式(多線程實現的方式3)
1.自定義類,實現Callable接口;
2.重寫call()方法;(有返回值了)
3.啓動:
使用線程組的方式啓動線程;
七.定時器:
1.TimersTask(抽象類):定義任務
1).自定義類,繼承自TimerTask;
2).重寫run()方法;
2.Timer類:
構造方法:Timer();
執行任務:
public void schedule(TimerTask task, long delay):在delay毫秒後執行一次;
public void schedule(TimerTask task,long delay,long period):在delay毫秒後開始執行,並每間隔period毫秒後會重複執行;
八.設計模式:
1.簡單工廠模式:
1.定義具體產品類;
2.定義工廠類;
3.在工廠類中提供針對每個產品的get方法,或者提供一個方法獲取所有產品;
優點:前端無需直接面對具體的產品,只需要通過工廠獲取具體產品就可以;
缺點:每增加一個新產品,都要修改工廠類;
2.工廠方法模式:
1.定義產品的接口;
2.定義工廠的接口;
3.增加一個產品時,定義產品類,實現"產品接口",定義工廠類,實現"工廠接口"。
優點:新增產品時,對原類無需任何修改;
缺點:類太多;
3.單例模式--餓漢式:
class Student{
prviate static Student stu = new Student();
private Student(){
}
public static Student getStudent(){
return stu;
}
}
4.單例模式--懶漢式:
class Student{
private static Student stu = null;
private Student(){
}
public synchronized static Student getStudent(){
if(stu == null){
stu = new Student();
}
return stu;
}
}
package com.heima.exam;
class StopThreadTest {
public static void main(String[] args) {
ThreadInStop t1 = new ThreadInStop();
t1.start();
int index = 0;
while(true) {
if(index++ == 500){
t1.stopThread();
t1.interrupt();
break;
}
System.out.println(Thread.currentThread().getName());
}
System.out.println("main() exit");
}
}
class ThreadInStop extends Thread {
private boolean bStop = false;
public synchronized void run() {
while(!bStop) {
try {
wait();
} catch(InterruptedException e) {
if(bStop) {
return;
}
}
System.out.println(getName());
}
}
public void stopThread() {
bStop = true;
}
}