1.發揮多處理的強大能力
2.建模的簡單性
3.異步事件的簡化處理
4.響應更加靈敏的用戶界面java
多線程環境下
多個線程共享一個資源
對資源進行非原子性操做編程
一、死鎖
二、飢餓
飢餓與公平
1)高優先級吞噬全部低優先級的CPU時間片
2)線程被永久堵塞在一個等待進入同步塊的狀態
3)等待的線程永遠不被喚醒
如何儘可能避免飢餓問題 數組
三、活鎖緩存
線程在必定條件下,狀態會發生變化。線程一共有如下幾種狀態:安全
一、新建狀態(New):新建立了一個線程對象。多線程
二、就緒狀態(Runnable):線程對象建立後,其餘線程調用了該對象的start()方法。該狀態的線程位於「可運行線程池」中,變得可運行,只等待獲取CPU的使用權。即在就緒狀態的進程除CPU以外,其它的運行所需資源都已所有得到。併發
三、運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。dom
四、阻塞狀態(Blocked):阻塞狀態是線程由於某種緣由放棄CPU使用權,暫時中止運行。直到線程進入就緒狀態,纔有機會轉到運行狀態。異步
阻塞的狀況分三種:ide
(1)、等待阻塞:運行的線程執行wait()方法,該線程會釋放佔用的全部資源,JVM會把該線程放入「等待池」中。進入這個狀態後,是不能自動喚醒的,必須依靠其餘線程調用notify()或notifyAll()方法才能被喚醒,
(2)、同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM會把該線程放入「鎖池」中。
(3)、其餘阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置爲阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。
五、死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命週期。
線程變化的狀態轉換圖以下:
public class Demo1 extends Thread { public Demo1(String name) { super(name); } @Override public void run() { while(!interrupted()) { System.out.println(getName() + "線程執行了 .. "); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Demo1 d1 = new Demo1("first-thread"); Demo1 d2 = new Demo1("second-thread"); d1.start(); d2.start(); // d1.stop(); d1.interrupt(); } }
二、實現Runnable接口
public class Demo2 implements Runnable { @Override public void run() { while(true) { System.out.println("thread running ..."); } } public static void main(String[] args) { Thread thread = new Thread(new Demo2()); thread.start(); } }
三、匿名內部類的方式
public class Demo3 { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { System.out.println("runnable"); } }) { public void run() { System.out.println("sub"); }; }.start(); } }
四、帶返回值的線程
import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class Demo4 implements Callable<Integer> { public static void main(String[] args) throws Exception { Demo4 d = new Demo4(); FutureTask<Integer> task = new FutureTask<>(d); Thread t = new Thread(task); t.start(); System.out.println("我先乾點別的。。。"); Integer result = task.get(); System.out.println("線程執行的結果爲:" + result); } @Override public Integer call() throws Exception { System.out.println("正在進行緊張的計算...."); Thread.sleep(3000); return 1; } }
五、定時器(quartz)
import java.util.Timer; import java.util.TimerTask; public class Demo5 { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { // 實現定時任務 System.out.println("timertask is run"); } }, 0, 1000); } }
六、線程池的實現
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 線程池 * @author Administrator * */ public class Demo6 { public static void main(String[] args) { ExecutorService threadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 1000; i++) { threadPool.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } threadPool.shutdown(); } }
七、Lambda表達式實現
import java.util.Arrays; import java.util.List; /** * lambda並行計算 * @author Administrator * */ public class Demo7 { public static void main(String[] args) { List<Integer> values = Arrays.asList(10,20,30,40); int res = new Demo7().add(values); System.out.println("計算的結果爲:" + res); } public int add (List<Integer> values) { values.parallelStream().forEach(System.out :: println); return values.parallelStream().mapToInt( i -> i * 2).sum(); } }
一、內置鎖
二、互斥鎖
一、修飾普通方法
二、修飾靜態方法
三、修飾代碼塊
public class Sequence { private int value; /** * synchronized 放在普通方法上,內置鎖就是當前類的實例 * @return */ public synchronized int getNext() { return value ++; } /** * 修飾靜態方法,內置鎖是當前的Class字節碼對象 * Sequence.class * @return */ public static synchronized int getPrevious() { // return value --; return 0; } public int xx () { // monitorenter synchronized (Sequence.class) { if(value > 0) { return value; } else { return -1; } } // monitorexit } public static void main(String[] args) { Sequence s = new Sequence(); // while(true) { // System.out.println(s.getNext()); // } new Thread(new Runnable() { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }
對象頭中的信息
Mark Word:線程id、Epoch、對象的分代年齡信息、是不是偏向鎖、鎖標誌位
Class Metadata Address
Array Length
每次獲取鎖和釋放鎖會浪費資源
不少狀況下,競爭鎖不是由多個線程,而是由一個線程在使用。
只有一個線程在訪問同步代碼塊的場景
public class Target implements Runnable { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " ..."); // Thread.sleep(1); } } }
public class Demo { public static void main(String[] args) { Thread t1 = new Thread(new Target()); Thread t2 = new Thread(new Target()); t1.setPriority(1); t2.setPriority(Thread.MIN_PRIORITY); t1.start(); t2.start(); } }
沒有線程安全性問題
public class Singleton { // 私有化構造方法 private Singleton () {} private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } }
懶漢式
雙重檢查加鎖解決線程安全性問題
public class Singleton2 { private Singleton2() {} //volatile 解決指令重排序致使的線程安全性問題、過多將致使cpu緩存優化失效 private static volatile Singleton2 instance; /** * 雙重檢查加鎖 * * @return */ public static Singleton2 getInstance () { // 自旋 while(true) if(instance == null) { synchronized (Singleton2.class) { if(instance == null) { instance = new Singleton2(); // 指令重排序 // 申請一塊內存空間 // 1 // 在這塊空間裏實例化對象 // 2 // instance的引用指向這塊空間地址 // 3 } } } return instance; } }
9、鎖重入
public class Demo { public synchronized void a () { System.out.println("a"); // b(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void b() { System.out.println("b"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { //同一個對對象將會阻塞 Demo d1= new Demo(); Demo d2= new Demo(); new Thread(new Runnable() { @Override public void run() { d1.a(); } }).start(); new Thread(new Runnable() { @Override public void run() { d2.b(); } }).start(); } }
10、自旋鎖
import java.util.Random; /** * 多個線程執行完畢以後,打印一句話,結束 * @author worker * */ public class Demo2 { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 線程執行..."); try { Thread.sleep(new Random().nextInt(2000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 線程執行完畢了..."); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 線程執行..."); try { Thread.sleep(new Random().nextInt(2000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 線程執行完畢了..."); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 線程執行..."); try { Thread.sleep(new Random().nextInt(2000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 線程執行完畢了..."); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 線程執行..."); try { Thread.sleep(new Random().nextInt(2000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 線程執行完畢了..."); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 線程執行..."); try { Thread.sleep(new Random().nextInt(2000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 線程執行完畢了..."); } }).start(); while(Thread.activeCount() != 1) { // 自旋 } System.out.println("全部的線程執行完畢了..."); } }
11、死鎖
public class Demo3 { private Object obj1 = new Object(); private Object obj2 = new Object(); public void a () { synchronized (obj1) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj2) { System.out.println("a"); } } } public void b () { synchronized (obj2) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj1) { System.out.println("b"); } } } public static void main(String[] args) { Demo3 d = new Demo3(); new Thread(new Runnable() { @Override public void run() { d.a(); } }).start(); new Thread(new Runnable() { @Override public void run() { d.b(); } }).start(); } }
Volatile稱之爲輕量級鎖,被volatile修飾的變量,在線程之間是可見的。
可見:一個線程修改了這個變量的值,在另一個線程中可以讀到這個修改後的值。
Synchronized除了線程之間互斥意外,還有一個很是大的做用,就是保證可見性
public class Demo2 { public volatile boolean run = false; public static void main(String[] args) { Demo2 d = new Demo2(); new Thread(new Runnable() { @Override public void run() { for(int i = 1;i<=10;i++) { System.err.println("執行了第 " + i + " 次"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } d.run = true; } }).start(); new Thread(new Runnable() { @Override public void run() { while(!d.run) { // 不執行 } System.err.println("線程2執行了..."); } }).start(); } }
在多處理器的系統上
一、將當前處理器緩存行的內容寫回到系統內存
二、這個寫回到內存的操做會使在其餘CPU裏緩存了該內存地址的數據失效
硬盤 – 內存 – CPU的緩存
多個線程能夠同時
public class User { private String name; public volatile int old; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getOld() { return old; } public void setOld(int old) { this.old = old; } }
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicIntegerArray; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReference; public class Sequence { private AtomicInteger value = new AtomicInteger(0); private int [] s = {2,1,4,6}; AtomicIntegerArray a = new AtomicIntegerArray(s); AtomicReference<User> user = new AtomicReference<>(); AtomicIntegerFieldUpdater<User> old = AtomicIntegerFieldUpdater.newUpdater(User.class, "old"); /** * @return */ public int getNext() { User user = new User(); System.out.println(old.getAndIncrement(user)); System.out.println(old.getAndIncrement(user)); System.out.println(old.getAndIncrement(user)); a.getAndIncrement(2); a.getAndAdd(2, 10); return value.getAndIncrement(); } public static void main(String[] args) { Sequence s = new Sequence(); new Thread(new Runnable() { @Override public void run() { // while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // } } }).start(); } }
Lock須要顯示地獲取和釋放鎖,繁瑣能讓代碼更靈活
Synchronized不須要顯示地獲取和釋放鎖,簡單
使用Lock能夠方便的實現公平性
非阻塞的獲取鎖
能被中斷的獲取鎖
超時獲取鎖
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Sequence { private int value; Lock lock = new ReentrantLock(); Lock l1 = new ReentrantLock(); /** * @return */ public int getNext() { lock.lock(); int a = value ++; lock.unlock(); return a; } public static void main(String[] args) { Sequence s = new Sequence(); new Thread(new Runnable() { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }