程序是一段靜態的代碼,進程是程序的一次動態執行過程,這個過程也是進程自己從產生、發展至消亡的過程。java
線程不是進程,是比進程更小的執行單位。但與進程不一樣的是,線程的中斷和恢復能夠更加節省系統的開銷。git
沒有進程就沒有線程。多線程
Java語言的一大特性點就是內置對多線程的支持。學習
多線程是指一個應用程序中同時存在幾個執行本,按幾條不一樣的執行線索共同工做的狀況。ui
計算機在任何給定的時刻只能執行線程中的一個。Java虛擬機快速地把控制從一個線程切換到另外一個線程,這些線程被輪流執行,使得每一個線程都有機會使用CPU資源。線程
如- 果main方法中沒有建立其餘的線程,那麼當main方法執行完最後一個語句,即main方法返回時,JVM就會結束Java應用程序。若是main方法中又建立了其餘線程,那麼JVM就要在主線程和其餘線程之間輪流切換,保證,每一個線程都有機會使用CPU,main方法即便執行完最後的語句(主線程結束),JVM也不會結束Java應用程序,JVM一直要等到Java應用程序都結束以後,才結束Java應用程序。3d
Java語言使用Thread類及其子類的對象來表示線程。rest
新建的線程在一個完整的生命週期中一般要經歷如下4個狀態:orm
新建:一個Thread類或其子類的對象被聲明並建立,已經有了相應的內存空間和其餘資源。對象
運行:JVM將CPU使用權切換給該線程時,此線程就能夠脫離建立它的主線程獨立開始本身的生命週期了。
若是線程是Thread的子類建立的,該類中的run()方法就馬上執行,且程序必須在子類中重寫父類的run()方法。
在線程沒有結束run()方法以前,不要讓線程再調用start()方法,不然將發生IllegalThreadStateException異常。
每一個Java線程的優先級都在常數1和10之間,即Thread.MIN_PRIORITY 和Thread.MAX_PRIORITY之間。若是沒有明確地設置線程的優先級別,,每一個線程的優先級都爲常數5,即Thread.NORM_PRIORITY。
能夠經過setPriority(int grade)方法調整優先級, getPriority 方法返回線程的優先級。
當線程使用CPU資源的時間到時後,即便線程沒有完成本身的所有操做,JVM也會中斷當前線程的執行,把CPU的使用權切換給下一個排隊等待的線程,當前線程將等待CPU資源的下一次輪迴,而後從中斷處繼續執行。
JVM的線程調度器的任務是使高優先級的線程能始終運行,一旦時間片有空閒,則使具備同等優先級的線程以輪流的方式順序使用時間片。
在編寫Thread類的子類時,須要重寫父類的run()方法。
優勢:能夠在子類中增長新的成員變量,實現城具備某種屬性,也能夠在子類中新增長方法,使線程具備某種功能。
Java不支持多繼承,Thread類的子類不能再擴展其餘的類。
在建立線程對象時必須向構造方法的參數傳遞一個實現Runnable接口類的實例,該實例對象稱做所創線程的目標對象,當線程調用start()方法後,一旦輪到它來享用CPU資源,目標對象就會自動調用接口中的run()方法(接口回調)
對於使用同一目標對象的線程,目標對象的成員變量天然就是這些線程共享的數據單元,使用Runnable接口比使用Thread的子類更具備靈活性。
run(): Thread類的run()方法與Runnable接口中的run()方法的功能和做用相同,都用來定義線程對象被調度以後所執行的操做,都是系統自動調用而用戶程序不得引用的方法。
sleep(int millsecond): 優先級高的線程能夠在它的run()方法中調用sleep方法來使本身放棄CPU資源,休眠一段時間。
isAlive(): 線程處於「新建」狀態時,線程調用isAlive()方法返回false。在線程的run()方法結束以前,即沒有進入死亡狀態以前,線程調用isAlive()方法返回true。
多個線程調用synchronized方法必須遵照同步機制。
在處理線程同步時,要作的第一件事就是要把修改數據的方法用關鍵字synchronized來修飾。
所謂線程同步就是若干個線程都須要使用一個synchronized修飾的方法。
線程同步機制:當一個線程A使用synchronized方法時,其餘線程想使用這個synchronized方法時就必須等待,直到線程A使用完該synchronized方法。
wait()方法能夠中斷方法的執行,使本線程等待,暫時讓出CPU的使用權,並容許其它線程使用這個同步方法。
notifyAll()方法通知全部的因爲使用這個同步方法而處於等待的線程結束等待。曾中斷的線程就會從剛纔的中斷處繼續執行這個同步方法,並遵循「先中斷先繼續」的原則。
notify()方法只是通知處於等待中的線程的某一個結束等待。
wait()、notify()、notifyAll()都是Object類中的final方法,被全部的類繼承且不容許重寫得方法。不能夠在非同步方法中使用wait()、notify()、notifyAll()。
當Java程序包含圖形用戶界面(GUI)時,Java虛擬機在運行應用程序會自動啓動更多的線程
使用Timer類的方法start()啓動計時器,即啓動線程。
使用Timer類的方法stop()中止計時器,即掛起線程。
使用restart()從新啓動計時器,即恢復線程。
使用Timer(int a,Object b)建立一個計時器,計時器每隔a毫秒「震鈴」一次,參數b是計時器的監視器。計時器發生的震鈴事件是ActinEvent類型事件。當震鈴事件發生時,監視器就會監視到這個事件,監視器就回調ActionListener接口中的actionPerformed(ActionEvent e)方法。
注:計時器的監視器必須是組件類(例如JFrame、JButton等)的子類的實例,不然計時器沒法啓動。
線程默認是非守護線程(即用戶(user)線程)。
一個線程調用void setDaemon(boolean on)方法能夠將本身設置成一個守護(Daemon)線程,例如:thread.setDaemon(true);
當程序中的全部用戶線程都已結束運行時,即便守護線程的run方法中還有須要執行的語句,守護線程也馬上結束運行。
用戶線程與守護線程的區別在於虛擬機的離開。若是用戶線程已經所有退出運行,只剩下守護線程存在,那麼虛擬機也就退出了。
一個線程必須在運行前設置本身是不是守護線程。
問題:在運行Example12_4時,出現了剩下的水變多的狀況
解決:與同窗討論後得出結論,在程序執行「貓」時,水量減1,而後此時程序切換到「狗」,水量又減2,而後輸出「狗」中的剩水量7,而後又切換到「貓」,此時「貓」中的水量並無更新,要等到下一個while循環才更新,而後輸出剩水量9。後面的過程以此類推。