Java有兩種方式建立線程, 繼承Thread類和實現Runnable接口ide
步驟:this
1.自定義一個類繼承Thread類, 重寫run方法
2.建立自定義類的對象,調用start()
例如:spa
class MyThread extends Thread { @Override public void run() { System.out.println("in thread"); } } MyThread thread = new MyThread(); thread.start();
步驟:線程
1. 自定義一個類,實現Runnable,重寫run()
2.建立一個Thread對象, 構造方法的參數是自定義類的對象, 調用start()
例如:code
class MyRunnable implements Runnable { @Override public void run() { System.out.println("in Runable"); } } MyRunnable runnable = new MyRunnable(); new Thread(runnable).start();
買5張火車票,咱們但願多個線程總共買5張票, 下面是兩種實現的代碼對象
繼承Thread: blog
class MyThread extends Thread { private int ticket = 5; @Override public void run() { for (int i=0;i<10;i++) { if(ticket > 0){ System.out.println("ticket = " + ticket--); } } } } new MyThread().start(); new MyThread().start();
咱們new了2個線程對象,分別獨立的執行2個對象中的代碼繼承
控制檯輸出: 忽略輸出順序,能夠看出2個線程分別賣了5張接口
ticket = 5 ticket = 4 ticket = 3 ticket = 5 ticket = 2 ticket = 4 ticket = 3 ticket = 2 ticket = 1 ticket = 1
實現Runnable接口:資源
class MyRunnable implements Runnable { private int ticket = 5; @Override public void run() { for (int i=0;i<10;i++) { if(ticket > 0){ System.out.println("ticket = " + ticket--); } } } } MyRunnable r = new MyRunnable(); new Thread(r).start(); new Thread(r).start();
兩個Thread對象共享一個Runnable對象
控制檯輸出: 能夠看出2個線程共買了5張, 達到了資源共享的目的
ticket = 5 ticket = 4 ticket = 3 ticket = 2 ticket = 1
經過上面的案例, 能夠總結出:
1.數據可以被多個線程共享,實現了代碼與數據是獨立的
2.適合多個相同程序代碼的線程區處理同一資源的狀況
線程的中斷是一種協做機制,線程中斷後並不必定當即中斷,而是要求線程在合適的時間中斷本身,每一個線程都有一個boolean的中斷標誌,該屬性再也不Thread中
interrupt() : 只是設置線程的中斷標誌
public static void main(String[] args) { Runnable r = new Runnable() { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { //若是去掉這句, 下面的輸出語句就會答應 return; } System.out.println("中斷"); } }; Thread t = new Thread(r); t.start(); //主線程休眠,確保剛纔啓動的線程執行一段時間 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } //中斷線程 t.interrupt();
在主線程中啓動新線程, 主線程休眠2秒鐘, 新線程休眠5秒鐘
2秒後主線程會中斷新線程,新線程的休眠狀態被打斷, 拋出 InterruptedException
程序進入catch塊中,執行return語句, 從run()返回,而後線程消亡
interrupted() : 線程中斷返回true, 並清除線程狀態
isInterrupted(): 線程中斷返回true, 不能改變線程的狀態
public static void main(String[] args) { System.out.println(Thread.interrupted()); //中斷 Thread.currentThread().interrupt(); System.out.println(Thread.interrupted()); System.out.println(Thread.interrupted()); } //控制檯輸出: false true false
也就是說, interrupted()會改變中斷狀態
join() : 在A線程中,調用B線程對象的該方法, 那麼A線程等B線程執行完後再執行
public static int a = 0; public static void main(String[] args) throws Exception { Runnable r = new Runnable(){ @Override public void run() { for (int k = 0; k < 5; k++) { a = a + 1; } System.out.println("a" + a); } }; Thread t = new Thread(r); t.start(); t.join(); for (int i=0; i<1; i++) { System.out.println("i=" + i); } }
控制檯輸出: a=5 i=0;
若是把 t.join()該行去掉, 則輸出 i=0 a=5 ; 由於主線程首先得到時間片執行, 而後在執行其它線程
經過Object類的wait(), notify(), notifyAll()能夠實現線程間的通訊
wait() : 將當前線程置入休眠狀態,直到接到通知或被中斷爲止
notify() : 若是有多個線程等待,則線程規劃器任意挑選出其中一個wait()狀態的線程來發出通知
nofityAll() : 使全部原來在該對象上wait的線程通通退出wait的狀態
生產者和消費者在同一時間段共享同一存儲空間, 生產者向空間內生產數據,消費者取出數據
下面是個例子:
public class ProductConsumer{ public static void main(String[] args) { Shared s = new Shared(); new Producer(s).start(); new Consumer(s).start(); } } /** 負責存儲數據 */ class Shared { private char c; private volatile boolean writeable = true; synchronized void setSharedChar(char c) { while (!writeable) try { wait(); } catch (InterruptedException ie){ } this.c = c; System.out.println(c + " produced by producer."); writeable = false; notify(); } synchronized char getSharedChar(){ while (writeable) try{ wait(); } catch (InterruptedException ie){ } writeable = true; notify(); System.out.println(c + " consumed by consumer."); return c; } } /** 生產者 */ class Producer extends Thread{ private final Shared s; Producer(Shared s){ this.s = s; } @Override public void run() { for (char ch = 'A'; ch <= 'Z'; ch++){ synchronized (s) { s.setSharedChar(ch); } } } } /** 消費者 */ class Consumer extends Thread { private final Shared s; Consumer(Shared s) { this.s = s; } @Override public void run() { char ch; do { synchronized (s) { ch = s.getSharedChar(); } } while (ch != 'Z'); } }
控制檯輸出:
A produced by producer.
A consumed by consumer.
...................
如今咱們能建立線程, 並能改變線程的狀態,下圖是對線程狀態的總結