本文關鍵詞:
java 多線程 概念 進程 線程區別聯系 java創建線程方式 線程組 線程池概念 線程安全 同步 同步代碼塊 Lock鎖 sleep()和wait()方法的區別 為什么wait(),notify(),notifyAll()等方法都定義在Object類中
多線程
•進程:
•正在運行的程序,是系統進行資源分配和調用的獨立單位。
•每一個進程都有它自己的內存空間和系統資源。
•線程:
•是進程中的單個順序控制流,是一條執行路徑
•一個進程如果只有一條執行路徑,則稱為單線程程序。
•一個進程如果有多條執行路徑,則稱為多線程程序。
多進程的意義?
提高CPU的使用率
多線程的意義?
提高應用程序的使用率
Java程序運行原理
•java命令會啟動 java 虛擬機,啟動 JVM,等於啟動了一個應用程序,也就是啟動了一個進程。
該進程會自動啟動一個 “主線程” ,然后主線程去調用某個類的 main方法。
所以 main方法運行在主線程中。在此之前的所有程序都是單線程的。
java中對於線程的描述是Thread 其中封裝了線程的信息,最重要的還有需要執行的任務的信息
Thread類名的基本獲取和設置方法
•public final String getName()
•public final void setName(String name)
•其實通過構造方法也可以給線程起名字
創建線程方式一
繼承Thread類
1.子類覆蓋父類中的run方法,將線程運行的代碼存放在run中。2.建立子類對象的同時線程也被創建。3.通過調用start方法開啟線程。
創建線程方式二
實現Runnable接口
1.子類覆蓋接口中的run方法。2.通過Thread類創建線程,並將實現了Runnable接口的子類對象作為參數傳遞給Thread類的構造函數。3.Thread類對象調用start方法開啟線程。
啟動一個線程是run()還是start()?它們的區別?
start();
run():封裝了被線程執行的代碼,直接調用僅僅是普通方法的調用
start():啟動線程,並由JVM自動調用run()方法
線程的調度和優先級
線程的調度
分時調度
搶占式調度 (Java采用的是該調度方式)
獲取和設置線程優先級
默認是5
范圍是1-10
線程的控制方法
•線程休眠
•public static void sleep(long millis)
•線程加入
•public final void join()
•線程禮讓
•public static void yield()
•后台線程
•public final void setDaemon(boolean on)
•中斷線程
•public final void stop() 過時
•public void interrupt()
停止線程還可以通過定義循環控制標志來解決現成的停止問題
sleep()和wait()方法的區別
sleep():必須指時間;不釋放鎖。
wait():可以不指定時間,也可以指定時間;釋放鎖。
為什么wait(),notify(),notifyAll()等方法都定義在Object類中
因為這些方法的調用是依賴於鎖對象的,而同步代碼塊的鎖對象是任意鎖。
而Object代碼任意的對象,所以,定義在這里面。
多線程同時請求共享資源,並且操作的代碼不是原子操作的時候
就會出現多線程的安全問題
解決線程安全問題的基本思想
首先想為什么出現問題?(也是我們判斷是否有問題的標准)
•是否是多線程環境
•是否有共享數據
•是否有多條語句操作共享數據
如何解決多線程安全問題呢?
•基本思想:讓程序沒有安全問題的環境。
•怎么實現呢?
•把多個語句操作共享數據的代碼給鎖起來,讓任意時刻只能有一個線程執行即可。
同步
同步代碼塊
•格式:
synchronized(對象){需要同步的代碼;}
•同步可以解決安全問題的根本原因就在那個對象上。該對象如同鎖的功能。
同步方法
•就是把同步關鍵字加到方法上
同步方法的鎖對象是this
靜態同步方法所對象是類名.class 對象
Lock
Lock•void lock()•void unlock()ReentrantLock
線程組
Java中使用ThreadGroup來表示線程組,它可以對一批線程進行分類管理,Java允許程序直接對線程組進行控制。
•默認情況下,所有的線程都屬於主線程組。
•public final ThreadGroup getThreadGroup()
•我們也可以給線程設置分組
•Thread(ThreadGroup group, Runnable target, String name)
線程池
程序啟動一個新線程成本是比較高的,因為它涉及到要與操作系統進行交互。
而使用線程池可以很好的提高性能
尤其是當程序中要創建大量生存期很短的線程時,更應該考慮使用線程池。
•線程池里的每一個線程代碼結束后,並不會死亡,而是再次回到線程池中成為空閑狀態,等待下一個對象來使用。
•在JDK5之前,我們必須手動實現自己的線程池,從JDK5開始,Java內置支持線程池
JDK5新增了一個Executors工廠類來產生線程池,有如下幾個方法
•public static ExecutorService newCachedThreadPool()
•public static ExecutorService newFixedThreadPool(int nThreads)
•public static ExecutorService newSingleThreadExecutor()
•這些方法的返回值是ExecutorService對象,
該對象表示一個線程池,可以執行Runnable對象或者Callable對象代表的線程。它提供了如下方法
•Future<?> submit(Runnable task)
•<T> Future<T> submit(Callable<T> task)
實現Callable接口 也可以實現多線程
匿名內部類方式使用多線程
new Thread(){代碼…}.start();
New Thread(new Runnable(){代碼…}).start();
定時器
定時器是一個應用十分廣泛的線程工具,可用於調度多個定時任務以后台線程的方式執行。
在Java中,可以通過Timer和TimerTask類來實現定義調度的功能
Timer
•public Timer()
•public void schedule(TimerTask task, long delay)
•public void schedule(TimerTask task,long delay,long period)
TimerTask
•public abstract void run()
•public boolean cancel()
開發中
Quartz是一個完全由java編寫的開源調度框架。
線程類的其他方法
setPriority(int num)setDaemon(boolean b)join()自定義線程名稱toString()