em,據說多線程是面試的重點。第一次學習的時候,只是粗略的看了一下,不少概念並非很清楚。此次整理一下,省得白學java
進程面試
線程緩存
分時調度安全
搶佔式調度多線程
同步: 排隊執行 , 效率低可是安全.
異步: 同時執行 , 效率高可是數據不安全.併發
併發:指兩個或多個事件在同一個時間段內發生。
並行:指兩個或多個事件在同一時刻發生(同時發生)。異步
繼承Thread類:ide
public class ThreadDemo extends Thread{ public ThreadDemo(String name) { super(name); } @Override public void run() { System.out.println(Thread.currentThread().getName() + " Hello"); } public static void main(String[] args) { new ThreadDemo("自定義線程").start(); System.out.println(Thread.currentThread().getName() + " Hello"); } }
實現Runnable接口學習
public class RunnableDemo implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + " Hello"); } public static void main(String[] args) { new Thread(new RunnableDemo(), "自定義線程").start(); System.out.println(Thread.currentThread().getName() + " Hello"); } }
實現Runnable 與 集成Thread相比有以下優點:線程
- 經過建立任務,給線程分配任務實現多線程,更適合多線程同時執行相同的任務狀況
2. 避免單繼承帶來的侷限性
3. 任務與線程自己是分離的,提升了程序的健壯性
4. 後續學習的線程技術,只接受Runnable類型的任務,不接受Thread類型的線程
當多個線程操做同一個數據的時候會出現線程安全問題
public class Demo04 { /** * 線程安全問題 * * @param args */ private static int count = 100; public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { while (count > 0) { System.out.println(Thread.currentThread().getName() + ":" + "當前票數爲:" + count); count--; System.out.println(Thread.currentThread().getName() + ":" + "當前票數爲:" + count); } } }; new Thread(runnable, "線程一").start(); new Thread(runnable, "線程二").start(); new Thread(runnable, "線程三").start(); new Thread(runnable, "線程四").start(); } }
線程二:當前票數爲:100
線程三:當前票數爲:100
線程三:當前票數爲:98
線程一:當前票數爲:100
線程一:當前票數爲:97
...
線程三:當前票數爲:4
線程一:當前票數爲:5
線程一:當前票數爲:-2
線程三:當前票數爲:-1
線程二:當前票數爲:0
public class 同步代碼塊 { public static void main(String[] args) { Runnable runnable = new Runnable() { //隱式鎖 //鎖對象 private Object o = new Object(); private int count = 100; @Override public void run() { while (true) { synchronized (o) { if (count > 0) { System.out.println(Thread.currentThread().getName() + " count = " + count); count--; } else { break; } } } } }; new Thread(runnable, "線程一").start(); new Thread(runnable, "線程二").start(); new Thread(runnable, "線程三").start(); } }
public class 同步方法 { public static void main(String[] args) { Runnable runnable = new Runnable() { private int count = 100; @Override public void run() { while (true) { if (!reduce()){ break; } } } public synchronized boolean reduce() { if (count > 0) { System.out.println(Thread.currentThread().getName() + " count = " + count); count--; return true; } return false; } }; new Thread(runnable, "線程一").start(); new Thread(runnable, "線程二").start(); new Thread(runnable, "線程三").start(); } }
線程一 count = 100
線程一 count = 99
線程一 count = 98
線程一 count = 97
...
線程一 count = 87
線程一 count = 86
...
線程一 count = 4
線程一 count = 3
線程一 count = 2
線程一 count = 1
public class 顯示鎖 { /** * 顯示鎖: Lock 子類 ReentrantLock * * @param args */ public static void main(String[] args) { Runnable runnable = new Runnable() { private int count = 100; private Lock lock = new ReentrantLock(); @Override public void run() { while (true) { lock.lock(); if (count > 0) { System.out.println(Thread.currentThread().getName() + " count = " + count); count--; } else { break; } lock.unlock(); } System.out.println("bye"); } }; new Thread(runnable, "線程一").start(); new Thread(runnable, "線程二").start(); new Thread(runnable, "線程三").start(); } }
//接口定義 //Callable接口 public interface Callable<V> { V call() throws Exception; } //Runnable接口 public interface Runnable { public abstract void run(); }
若是併發的線程數量不少,而且每一個線程都是執行一個時間很短的任務就結束了,這樣頻繁建立線程 就會大大下降 系統的 效率,由於頻繁建立線程和銷燬線程須要時間. 線程池就是一個容納多個線程的容 器,池中的線程能夠反覆使用,省去了頻繁建立線程對象的操做,節省了大量的時間和資源。
線程池的好處
Java中的四種線程池 . ExecutorService
public class 緩存線程池 { /** * 緩存線程池. * (長度無限制) * 執行流程: * 1. 判斷線程池是否存在空閒線程 * 2. 存在則使用 * 3. 不存在,則建立線程 並放入線程池, 而後使用 */ public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " Java"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " Java"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " Java"); } }); } }
pool-1-thread-1 Java
pool-1-thread-2 Java
pool-1-thread-2 Java
public class 定長線程池 { /** 定長線程池. * (長度是指定的數值) * 執行流程: * 1. 判斷線程池是否存在空閒線程 * 2. 存在則使用 * 3. 不存在空閒線程,且線程池未滿的狀況下,則建立線程 並放入線程池, 而後使用 * 4. 不存在空閒線程,且線程池已滿的狀況下,則等待線程池存在空閒線程 */ public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(2); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " Java"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " Java"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " Java"); } }); service.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " Java"); } }); } }
pool-1-thread-1 Java
pool-1-thread-2 Java
pool-1-thread-1 Java
pool-1-thread-2 Java