由於昨天看一則關於Synchronized(線程安全的帖子),只是以爲有些奇怪,其實當你明白一些基礎後,你徹底就能夠自學Java了,可是OO的思想是要經過大量的實例以及實踐造成的。(其實個人OO思想也不是很強烈,也正如neo_q牛人所說:"簡單地說繼承、封裝、多態,在咱們的程序中都應該是要能體現出來的")。
我在看線程的時候,並沒以爲有多麼困難,也多是我學的根本就不深刻。下面進入正題:
線程簡介:
談到線程,就必然要提到另外一個概念,那就是進程。通常能夠在同一時間內執行多個程序的操做系統都有進程的概念。一個進程就是一個執行中的程序,而每個進程都有本身獨立的一塊內存空間、一組系統資源。在進程概念中,每個進程的內部數據和狀態都是徹底獨立的。Java經過流控制來執行程序流,程序中單個順序的流控制稱爲線程,多線程則意味着一個程序的多行語句能夠幾乎在同一時間內同時運行。(爲何是幾乎,不是同時,涉及到計算機原理,暫很少講)
線程與進程類似,是一段完成某個特定功能的代碼,是程序中單個順序的流控制;但與進程不一樣的是,同類的多線程是共享一塊內存空間和一組系統資源,而線程自己的數據一般只有CPU的寄存器數據,以及一個供程序執行時使用的堆棧。因此係統在產生一個線程,或者在各個線程之間切換時,負擔要比進程小的多,因此線程能夠被看做是輕量級的進程。一個進程中能夠包含多個線程,一個線程是一個程序內部的順序控制流。
做爲Java的一個重要的特性,Java內在支持多線程,它的全部類都是在多線程下定義的、Java利用多線程使整個系統成爲異步系統。Java中的線程由3個部分組成:虛擬的CPU、CPU所執行的代碼和CPU所處理的數據。
線程體的概念:
虛擬的CPU被封裝在java.lang.Thread類中,這樣CPU所執行的代碼和CPU所處理的數據都傳遞給java.lang.Thread類的實例中。因此Java的線程是經過java.lang.Thread類來實現的。當咱們生成一個Thread 類的對象後,一個新線程就產生了。現成實例表示Java解釋器中的真正的線程,經過它能夠啓動線程、終止線程、線程掛起等。每一個線程都是經過某個特定Thread對象的方法run()來完成其操做的,方法run()稱爲線程體。
Thread類有8個構造函數:略……API中明確寫出
Thread類的經常使用方法:(新手經常使用)
static Thread currentThread() //靜態方法,經過這個方法能夠得到主線程的引用,從而達到操做主線程的目的。(什麼是主線程?參見主線程)
static int activeCount() //靜態方法,得到當前活動線程數量
long getId() //得到當前線程id
String getName() //得到當前線程名字
int getPriority() //得到優先級
boolean isAlive() //當前線程是否處於活動狀態。
boolean isDaemon()//是否爲守護線程
void run()//run()方法,咱們用線程,主要就是對run()方法的重寫
void start() // 使該線程開始執行;Java 虛擬機調用該線程的run() 方法。
void sleep() //使當前線程休眠,以執行其餘線程,如Thread.sleep(1000) 休眠1秒
其實這些方法API中都有,並且寫的都很詳細,就很少說了。
線程體的自定義:
Java 中使用線程無非就是對run()方法的重寫,你能夠經過繼承Thread類或者使用Runnable接口來定義你本身的線程。因爲Java的單一繼承,因此提供了Runable接口。
=======================================================================
寫幾個簡單的例子:
class MyThread extends Thread{//繼承Thread實現線程,可是此類將不能再繼承別類。
public myThread(String name){
super(name);
}//這是myThread的構造方法,將name傳給Thread,name即自定義線程名字
public void run(){
System.out.println("This is myThread :"+this.getName());
for(int i=0;i<10;i++)
System.out.println("This is myThread :"+this.getName()+" : "+i);
}//run()方法的重寫
}
public class ThreadDemo{
public static void main(String [] args){
MyThread mt = new MyThread("線程1"); //實例化線程1,下文引用的①
MyThread mt1 = new MyThread("線程2");//實例化線程2
mt.start();//線程1運行,下文引用的②
mt1.start();//線程2運行
}
}
=====================================================================
class MyThread implements Runnable{ //接口實現線程
private Thread myThread = null;
public myThread(String name){
super();
this.myThread = new Thread(this,name);
}//這是myThread的構造方法。
public void start(){
myThread.start();
}//因爲接口Runnable中,只有一個抽象run()方法,因此咱們要定義一個start()方法,使當前線程運行。
public void run(){
System.out.println("This is myThread :"+this.getName());
for(int i=0;i<10;i++)
System.out.println("This is myThread :"+this.getName()+" : "+i);
}//run()方法的重寫
}
//main()方法基本同樣,就不寫了,因爲以上代碼都是在這裏寫的,在baidu blog中tab很差使,因此……醜
//這裏我主要想說明的是線程的兩種實現方式,一是繼承Thread,二使用Runnable接口。
==========================================================================
線程的狀態:
線程的狀態有4種:建立狀態、可執行狀態、不可執行狀態、死亡狀態。
建立狀態:實例化線程對象後,線程就處於建立狀態,此時系統不爲它分配資源。接上文①位置。
可執行狀態:當調用了run()方法後,線程就處於可運行狀態,系統爲他分配了它須要的系統資源。這裏要注意可運行與運行之分,調用了run()方法,並不表明它正在運行,同一時刻只能運行處於可運行狀態的的線程中的一個。
不可運行狀態:不可運行狀態也稱爲組塞狀態,因爲某中圓心繫統不能執行線程的狀態。在這種狀況下,即使CPU空閒,線程也不能被執行。線程成爲不可能運行狀態可能由於:Ⅰ.調用了sleep()方法。Ⅱ.調用了suspend()方法。Ⅲ.調用了wait()方法。Ⅳ.輸入輸出流中發生線程阻塞。
死亡狀態:線程執行完會自動進入死亡狀態或是調用了stop()方法都會進入死亡狀態。stop()方法已通過時。
主線程:
Java程序啓動運行時JVM會自動建立一個現成,這個就是主線程。
主線程的重要性和特殊性表如今下面兩個方面:
1。他是產生其餘線程的線程。
2。它一般執行各類關閉操做,是最後結束的。
在這裏你能夠理解main()爲一個主線程。只有main()的產生,你才能夠new出新的myThread線程對象。
線程調度:
在沒有設置優先級的狀況下,Java提供了一個線程調度器來調度程序啓動後進入可運行狀態的全部線程。線程調度器按線程的優先級高低選擇優先級高的先執行。
線程調度是搶先式調度,即當前線程執行過程當中,一個更高級的線程進入可運行狀態,將暫停原線程的運行,去執行更高級的線程。
搶先式調度又分爲:時間片方式和獨佔方式。時間片方式能夠理解爲按必定時間執行各個處於可運行狀態的線程,當時間到時,不論是否執行完,都轉入對下一個線程的執行。獨佔方式則是指CPU始終在執行一個線程,只有當前線程執行完後或線程主動退出後,才轉入對下一個線程的執行。
線程優先級:
Java中線程有10個優先級,由低到高分別用1~10表示。Thread類中定義了3個靜態變量,分別是Thread.MIN_PRIORITY 表明最低優先級1,Thread.NORM_PRIORITY 普通5,Thread.MAX_PRIORITY 最高10
咱們能夠經過setPriority(),以及getPriority()對當前線程優先級進行操做。
假若有myThread0,myThread1,以及myThread二、三個線程同時處於可運行狀態,分別對應min、norm、max優先級,那CPU將會先執行優先級爲max、再執行norm、最後執行min的run()方法。
守護線程:(精靈線程)
線程默認都是非守護線程,非守護線程也稱作用戶線程。程序中當全部用戶線程都結束時,守護線程也當即結束。由於守護現成隨時會結束,因此守護線程所作的工做應該是能夠隨後結束而不該該運行結果的工做。
咱們經過setDaemon(boolean on)來設置當前線程是否爲守護線程。仍是上面的繼承Thread的例子,咱們再多寫一個MyThread2,其中run()方法爲
while(true)
System.out.println("This is Daemon Thread");
而且在main()中這樣寫
MyThread2 mtDaemon = new MyThread2("DaemonThread");
mtDaemon.start();
mtDaemon.setDaemon(true);
假如沒有setDaemon()這句,mtDaemon線程將進入死循環,並致使正個程序都不能中止,而若是設置了setDaemon()後當mt線程進入死亡狀態後,main()也結束時,mtDaemon也伴隨結束。通常守護線程能夠用於程序的自動更新什麼的。
線程同步:(線程安全)
當有多個線程共享一個變量時,須要確保資源在某一個時刻只有一個線程佔用,這個過程就是線程同步。
舉例說明:假若有3我的同時在撥打同1個電話號碼,這3我的比如3個可運行狀態的線程,都在撥打的電話號碼就是共享變量。而當前電話不可能被3我的同時撥通,只有第1個被接通人的電話掛斷,其餘2我的的1個才能被接進來,第2我的再掛斷電話,第3我的才能接近來。
這裏主要用到的就是synchronized關鍵字。我這裏有一個例子:
============================================================================
class PhoneCalls{
private String phoneName = "";
public PhoneCalls(String name) {
this.phoneName = name;
}
public void call(String name){
try{
System.out.println("<---"+name+"撥打"+this.phoneName+"電話--->");
Thread.sleep(1000);
System.out.println("<---"+name+"正在通話ing--->");
Thread.sleep(1000);
System.out.println("<---"+name+"掛斷電話--->");
}catch(Exception e){
e.printStackTrace();
}
}
}
public class SynCalls implements Runnable{
private String name = "";
private PhoneCalls phone = null;
private Thread thread = null;
public SynCalls(String name,PhoneCalls phone) {
this.name = name;
this.phone = phone;
this.thread = new Thread(this);
}
public void start(){
this.thread.start();
}
public void run() {
synchronized (this.phone) {
this.phone.call(this.name);
}
}
public static void main(String [] args){
PhoneCalls phone = new PhoneCalls("狗剩的電話");
SynCalls frist = new SynCalls("張三",phone);
SynCalls second = new SynCalls("李四",phone);
SynCalls third = new SynCalls("王五",phone);
frist.start();
second.start();
third.start();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.進一步鞏固java基礎。thinking in java必須看完,並且是一字不差地讀完,全部講到的知識點都要寫testcase,並且這本書最大的好處是在你不知不覺中培養你的OO思想,對你應該有所幫助,這本書至少讀兩遍,視你的狀況而定若是第二遍不能所有理解,那麼再來一輪直到真的所有理解,以後你能夠看看effective in java,爲何你到時候我相信會明白的。
2.逐步從寫出代碼到寫好代碼過渡。這個不是一蹴而就的,必定要在寫的過程當中慢慢培養一種思考方式和編程的習慣,那是什麼樣的習慣呢?重構的習慣,至於重構是怎麼會事情,簡單說就是寫完了重寫一遍,你千萬別以爲這個是麻煩事情,他的幫助是很大的,會告訴你若是下次遇到這樣的狀況,那麼你就會按照好的那種方法來寫。至於如何作到有兩本書能夠幫助你,Martin Fowler寫的《重構》,Steve McConnell《代碼大全》第二版。看完這兩本書,你會再上一個層次。
接下來還有很長的路,但願對你有所幫助,若是你以爲我這是廢話,那麼請徹底忽略。:) 另一句話,swing的東西仍是少作點,儘快轉向J2EE吧,畢竟外面的企業中仍是J2EE較多,可是若是你真的喜歡作桌面的話,或者興趣在此,那麼當我沒說。