進程: 進程是一個具備必定獨立功能的程序關於某個數據集合的一次運行活動,它是系統進行資源分配和調度的一個獨立單位。html
線程: 線程是進程的一個實體,是CPU調度和分配的基本單位。線程基本不擁有系統資源,與同一個進程的其餘線程共享進程中所擁有的全部資源。java
應用程序必須運行完全部的前臺線程才能夠退出;而對於後臺線程,應用程序則能夠不考慮其是否已經運行完畢而直接退出,全部的後臺線程在應用程序退出時都會自動結束。面試
第一種方式:直接繼承線程Thread類建立對象
1.Thread子類沒法再從其它類繼承(java語言單繼承)。
2.編寫簡單,run()方法的當前對象就是線程對象,可直接操做。c#
public MyThread extends Thread{ …… public void run() { 線程體邏輯 } } //建立及啓動線程: MyThread t = new MyThread(); t.start();
第二種方式:使用Runnable接口建立線程
1.能夠實現多個線程資源共享
2.線程體run()方法所在的類能夠從其它類中繼承一些有用的屬性和方法api
public MyThread implements Runnable { …… public void run() { 線程體邏輯 } } //建立及啓動線程: MyThread t = new MyThread(); Thread t1 = new Thread(t); t1.start();
線程安全:線程安全就是多線程訪問時,採用了加鎖機制,當一個線程訪問該類的某個數據時,進行保護,其餘線程不能進行訪問直到該線程讀取完,其餘線程纔可以使用。不會出現數據不一致或者數據污染。 線程不安全就是不提供數據訪問保護,有可能出現多個線程前後更改數據形成所獲得的數據是髒數據。
緣由是因爲不一樣線程獲取到資源時進行運算,但將來得及寫入時,線程改變,則另外線程讀入的資源就是錯誤,致使全部線程寫入讀入不一樣步。
解決辦法:緩存
線程同步通訊是但願實現兩個或多個線程之間的某種制約關係
實現:首先是用監視器synchronized來保證每次只有一個線程調用方法,其次引入一個boolean型標誌來判斷該線程是否執行或wait,兩個線程時使用notify(),多個線程時用notifyAll()來讓出監視器並喚醒其餘線程。這樣就實現了線程之間的關係。安全
//使用wait和notifyAll實現線程間同步通訊 (兩個存錢線程,一個取錢線程) class Account{ volatile private int value; //布爾標誌 volatile private boolean isMoney = false; //put設爲同步方法 synchronized void put(int i) { while(isMoney){ try{ wait();} //線程等待 catch(){Exception e}{} } value = value + i; System.out.println("存入"+i+" 帳上金額爲:"+value); isMoney = true;//設置標誌 notifyAll(); //喚醒等待資源的全部線程 } synchronized int get(int i) {//同步方法 while(!isMoney) ){ try { wait();} catch(){Exception e}{} } if (value>i) value = value - i; else { i = value; value = 0; } System.out.println("取走"+i+" 帳上金額爲:"+value); isMoney = false; notifyAll(); return i; } } class Save implements Runnable{ private Account a1; public Save(Account a1){this.a1 = a1;} public void run(){ while(true){ a1.put(100);} } } class Fetch implements Runnable { private Account a1; public Fetch(Account a1) { this.a1 = a1 ;} public void run(){ while(true){ a1.get(100);} } } public class TestCommunicate{ public static void main(String[] args){ Account a1 = new Account(); new Thread(new Save(a1)).start(); new Thread(new Save(a1)).start(); new Thread(new Fetch(a1)).start(); }}
若是多個線程都處於等待狀態,彼此須要對方所佔用的監視器全部權,多線程
就構成死鎖(deadlock),Java即不能發現死鎖也不能避免死鎖。ide
方法一:{ synchronized(A) { …. synchronized(B) { …. } } } 方法二:{ synchronized(B) { …. synchronized(A) { …. } } }
注意函數
可能發生死鎖的代碼執行中不必定會死鎖,由於線程之間的執行存
在很大的隨機性。
線程方法suspend()、resume()、stop()因爲存在引發死鎖的可能,
於是逐漸不用(Deprecated)。
class Account { volatile private int value; void put(int i) { synchronized(this) { value = value + i; System.out.println("存入"+i+" 帳上金額爲:"+value); } } synchronized int get(int i) { if (value>i) value = value - i; else { i = value; value = 0; } System.out.println("取走"+i+" 帳上金額爲:"+value); return i; } } class Save implements Runnable { int a=2000; private Account a1; public Save(Account a1) { this.a1 = a1; } public void run() { while(a-->0){ a1.put(100); } } } class Fetch implements Runnable { int a=2000; private Account a1; public Fetch(Account a1) {this.a1 = a1 ;} public void run() { while(a-->0){ a1.get(100); } } } public class Test{ public static void main(String[] args){ Account a1 = new Account(); new Thread(new Save(a1)).start(); new Thread(new Fetch(a1)).start(); } }
put方法的代碼塊被監視,get函數被監視,保證了value的正確性,輸出結果爲存錢取錢的隨機順序, 這裏沒有設置存取的制約關係。
public class test {//如何中斷線程?答案是添加一個開關。 private volatile static boolean on = false; //內部類 public class MyThreadTwo implements Runnable { @Override public void run() { try { System.out.println("into ---" + Thread.currentThread().getName()); Thread.sleep(10000);//因爲等待時間10秒,輸出多,上面的into語句被覆蓋了 System.out.println("out " + Thread.currentThread().getName()); test.on=true; } catch (InterruptedException e) { e.printStackTrace(); } } } private void start() { //一個Thread的構造函數接受一個Runnable參數,而傳入的lambda表達式正好符合其run()函數, // 因此Java編譯器推斷它爲Runnable。 Thread thread1 = new Thread(() -> { while (!on) { System.out.println(Thread.currentThread().getName()); } }); Thread thread2 = new Thread(new MyThreadTwo()); thread1.start(); thread2.start(); } public static void main(String[] args) { test test = new test(); test.start(); } }
class Cache { volatile private int value; final private int productSize; public Cache(int pro) { productSize = pro; } synchronized void put() {//存 while (value == productSize) {//緩存區產品長度滿時等待,不存 try { wait();//線程等待 } catch (InterruptedException e) { e.printStackTrace(); } } value = value + 1; System.out.println(Thread.currentThread().getName() + "存了" + 1+", 現value=" + value); notifyAll();//喚醒等待資源的全部線程 } synchronized void get() {//取 while (value == 0) {//緩存區產品長度空時等待,不取 try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } value = value - 1; System.out.println(Thread.currentThread().getName() + "取了" + 1+", 現value=" + value); notifyAll(); } } //生產者 class produce implements Runnable { private Cache a1; public produce(Cache a1) { this.a1 = a1; } public void run() { while (true) { a1.put(); } } } //消費者 class consumer implements Runnable { private Cache a1; public consumer(Cache a1) { this.a1 = a1; } public void run() { while (true) { a1.get(); } } } public class test{ public static void main(String[] args) { Cache a1=new Cache(20); //10個生產者 new Thread(new produce(a1)).start(); new Thread(new produce(a1)).start(); new Thread(new produce(a1)).start(); new Thread(new produce(a1)).start(); new Thread(new produce(a1)).start(); new Thread(new produce(a1)).start(); new Thread(new produce(a1)).start(); new Thread(new produce(a1)).start(); new Thread(new produce(a1)).start(); new Thread(new produce(a1)).start(); //10個消費者 new Thread(new consumer(a1)).start(); new Thread(new consumer(a1)).start(); new Thread(new consumer(a1)).start(); new Thread(new consumer(a1)).start(); new Thread(new consumer(a1)).start(); new Thread(new consumer(a1)).start(); new Thread(new consumer(a1)).start(); new Thread(new consumer(a1)).start(); new Thread(new consumer(a1)).start(); new Thread(new consumer(a1)).start(); } }
在這裏開始對volatile不是很瞭解其機制,記得老師講了i--
的操做三條指令,詳細瞭解了下,具體看: