class MyThread extends Thread { private String name; public MyThread(String name) { this.name = name; } @Override public void run() { //..... } } class Main { public static void main(String[] args) { MyThread a = new MyThread('A'); MyThread b = new MyThread('B'); a.start(); b.start(); } }
start 方法不能重複調用, 重複調用會出現java.lang.IllegalThreadStateException異常
html
class MyRunnable extend Runnable{ public MyRunnable() { } @Override public void run() { } } class Main { public static void main(String[] args) { MyRunnable a = new MyRunnable('A'); MyRunnable b = new MyRunnable('B'); Thread demoa = new Thread(a); Thread demob = new Thread(b); demoa.start(); demob.start(); } }
其實Thread也是實現Runnable接口的:java
class Thread implements Runnable { //… public void run() { if (target != null) { target.run(); } } }
Thread中的run方法調用的是Runnable接口的run方法。Thread和Runnable都實現了run方法,這種操做模式其實就是代理模式。多線程
若是一個類繼承Thread,則不適合資源共享。可是若是實現了Runable接口的話,則很容易的實現資源共享。ide
class MyThread implements Runnable{ private int ticket = 5; //5張票 public void run() { for (int i=0; i<=20; i++) { if (this.ticket > 0) { System.out.println(Thread.currentThread().getName()+ "正在賣票"+this.ticket--); } } } } public class lzwCode { public static void main(String [] args) { MyThread my = new MyThread(); new Thread(my, "1號窗口").start(); new Thread(my, "2號窗口").start(); new Thread(my, "3號窗口").start(); } }
實現Runnable接口比繼承Thread類所具備的優點:this
1):適合多個相同的程序代碼的線程去處理同一個資源
2):能夠避免java中的單繼承的限制
3):增長程序的健壯性,代碼能夠被多個線程共享,代碼和數據獨立。操作系統
在java中,每次程序運行至少啓動2個線程。一個是main線程,一個是垃圾收集線程。由於每當使用java命令執行一個類的時候,實際上都會啓動一個JVM,每個jVM就是在操做系統中啓動了一個進程。線程
主線程也有可能在子線程結束以前結束。而且子線程不受影響,不會由於主線程的結束而結束。代理
// 休眠兩秒 Thread.sleep(2000); // 強制加入 thread.join(); // 後臺線程 thread.setDaemon(true); /** * @author Rollen-Holt 後臺線程 * */ class hello implements Runnable { // 雖然有一個死循環,可是程序仍是能夠執行完的。由於在死循環中的線程操做已經設置爲後臺運行了。 public void run() { while (true) { System.out.println(Thread.currentThread().getName() + "在運行"); } } public static void main(String[] args) { hello he = new hello(); Thread demo = new Thread(he, "線程"); demo.setDaemon(true); demo.start(); } } // 優先級 // 不要誤覺得優先級越高就先執行。誰先執行仍是取決於誰先去的CPU的資源。 thread.setPriority(8); // 禮讓 // 在線程操做中,也可使用yield()方法,將一個線程的操做暫時交給其餘線程執行。 Thread.currentThread().yield();
/** * @author Rollen-Holt * */ class hello implements Runnable { public void run() { for(int i=0;i<10;++i){ if(count>0){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(count--); } } } public static void main(String[] args) { hello he=new hello(); Thread h1=new Thread(he); Thread h2=new Thread(he); Thread h3=new Thread(he); h1.start(); h2.start(); h3.start(); } private int count=5; } //【運行結果】: // 5 // 4 // 3 // 2 // 1 // 0 // -1
這裏出現了-1,顯然這個是錯的。應該票數不能爲負值。
若是想解決這種問題,就須要使用同步。所謂同步就是在統一時間段中只有有一個線程運行,其餘的線程必須等到這個線程結束以後才能繼續執行。code
使用同步代碼塊
和同步方法
htm
synchronized(同步對象){ //須要同步的代碼 }
/** * @author Rollen-Holt * */ class hello implements Runnable { public void run() { for(int i=0;i<10;++i){ synchronized (this) { if(count>0){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(count--); } } } } public static void main(String[] args) { hello he=new hello(); Thread h1=new Thread(he); Thread h2=new Thread(he); Thread h3=new Thread(he); h1.start(); h2.start(); h3.start(); } private int count=5; }
synchronized 方法返回類型方法名(參數列表){ // 其餘代碼 }
/** * @author Rollen-Holt * */ class hello implements Runnable { public void run() { for (int i = 0; i < 10; ++i) { sale(); } } public synchronized void sale() { if (count > 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(count--); } } public static void main(String[] args) { hello he = new hello(); Thread h1 = new Thread(he); Thread h2 = new Thread(he); Thread h3 = new Thread(he); h1.start(); h2.start(); h3.start(); } private int count = 5; }
當多個線程共享一個資源的時候須要進行同步,可是過多的同步可能致使死鎖。
/* *麪包類,用於存放廚師生產的麪包 */ public class Bread { private String producer; public Bread(String producer) { super(); this.producer = producer; } @Override public String toString() { return producer; } } /* * 籃子類,用於存放麪包 * 籃子假定最多放10個麪包 */ public class Basket { private int index = 0; private Bread[] arrayBread = new Bread[10]; /* * 此方法用於往籃子裏扔麪包 每當廚師生成好一個麪包就往籃子裏邊扔 因爲當某一個廚師在往籃子扔麪包的過程(還沒扔完,可是麪包已經在籃子裏), * 又有一個廚師要往籃子裏扔麪包。 若是這是籃子裏已經有9個麪包的話,最後一個廚師就不能在扔了。 * 因此須要給這個方法加把鎖,等一個廚師扔完後,另一個廚師才能往籃子裏扔。 */ public synchronized void push(int id, Bread bread) { System.out.println("生成前籃子裏有面包:" + index + " 個"); // 當廚師發現籃子滿了,就在那裏不停的等着 while (index == arrayBread.length) { System.out.println("籃子滿了,我開始等等。。。。。。"); try { // 廚師(一個生產線程)開始不停等待 // 他須要等待顧客(一個消費線程)把它叫醒 this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 喚醒一個正在等待的線程,若是喚醒的線程爲生產線程,則又會進入等待狀態, // 若是爲消費線程,則因生產線程生產了麪包的緣故,消費線程能夠進行消費 this.notify(); arrayBread[index] = bread; index++; System.out.println(bread); } /* * 此方法用於往籃子裏拿麪包 加鎖緣由和上邊同樣 */ public synchronized Bread pop(int id) { System.out.println("消費前籃子裏有面包:" + index + " 個"); while (index == 0) { System.out.println("籃子空了,我開始等等。。。。。。"); try { // 顧客(一個消費線程)開始不停等待 // 他須要等待廚師(一個生產線程)把它叫醒 this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 喚醒一個正在等待的線程,若是喚醒的線程爲消費線程,則又會進入等待狀態, // 若是爲生產線程,則因生產線程消費了麪包的緣故,生產線程能夠進行生產 this.notify(); index--; System.out.println("第" + id + "個顧客消費了 -->" + arrayBread[index]); return arrayBread[index]; } } /* * 廚師類,用於生產麪包 */ public class Kitchener implements Runnable { private Basket basket; private int id; public Kitchener(int id,Basket basket) { super(); this.id = id; this.basket = basket; } @Override public void run() { //讓廚師生產10個麪包 for (int i = 1; i <= 10; i++) { Bread bread = new Bread("第" + id + "個廚師生成的麪包"); basket.push(id,bread); try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /* * 顧客類,用於消費麪包 */ public class Customer implements Runnable { private Basket basket; private int id; public Customer(int id,Basket basket) { super(); this.id = id; this.basket = basket; } @Override public void run() { // 讓顧客消費10個麪包 for (int i = 1; i <= 10; i++) { basket.pop(id); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public class Test { public static void main(String[] args) { Basket basket = new Basket(); // 兩個廚師兩個客戶 Kitchener kitchener1 = new Kitchener(1,basket); Kitchener kitchener2 = new Kitchener(2,basket); Customer customer1 = new Customer(1,basket); Customer customer2 = new Customer(2,basket); new Thread(kitchener1).start(); new Thread(kitchener2).start(); new Thread(customer1).start(); new Thread(customer2).start(); } }
名字和年齡對應錯誤了,
http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html