1.進程與線程:java
線程:一個進程能夠擁有多個並行的線程,線程是進程中一個程序執行控制的單元linux
進程:由cpu,data,code三部分組成,每一個進程都是獨立的,由系統分配,進程間的切換開銷較大,進程基於操做系統;程序員
2.並行與併發redis
併發:多個線程訪問同一份資源算法
並行:在多個cpu情形下,多個線程同時運行api
3.線程數與運行時間數組
線程數:咱們看到的虛擬機裏面顯示的線程數,是虛擬的線程數,例如單線程,他是將時間分紅不少小的時間片,不一樣的時間片會調用不一樣的虛擬的線程程序段,當調用這個程序是其餘程序會掛起緩存
運行時間:運行時間與實際的線程數有直接聯繫,過多的線程容易引發併發等問題,因此不必定快安全
4.線程間的通訊多線程
通訊機制有兩種:共享內存和消息傳遞
共享內存的併發模型裏,線程之間共享程序的公共狀態,經過寫-讀內存中的公共狀態進行隱式通訊。在消息傳遞的併發模型裏,線程之間沒有公共狀態,線程之間必須經過發送消息來顯式進行通訊。Java的併發採用的是共享內存模型,Java線程之間的通訊老是隱式進行,整個通訊過程對程序員徹底透明,
5.內存的可見性
堆內存在線程之間共享。局部變量,方法定義參數和異常處理器參數不會在線程之間共享,它們不會有內存可見性問題,也不受內存模型的影響。線程之間的共享變量存儲在主內存中,每一個線程都有一個私有的本地內存,本地內存中存儲了該線程以讀/寫共享變量的副本。
6.實現多線程的3種方式
Thread類:
步驟:
1>定義類繼承Thread類;
2>複寫run方法;
3>建立Thread類的子類對象來建立線程對象;
4>調用線程的start方法,開啓線程,並執行run方法。
備註 : sleep 和wait的區別,一個會釋放鎖,一個不會釋放鎖
public class JoinTest { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread( new JoinTestA(),"線程1"); thread.start(); thread.join(); System.out.println("hello world"); } } class JoinTestA implements Runnable { @Override public void run() { System.out.println("hello join"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }
public class DaemonTest2 { public static void main(String[] args) { Thread thread = new Thread(new DaemonTestB() );
//設置爲守護線程的時候 ,須要是沒有開啓的線程,不然會報錯, thread.setDaemon(true); thread.start(); new Thread(new DaemonTestA() ).start(); } } class DaemonTestA implements Runnable { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(1111); } } class DaemonTestB implements Runnable { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(2222); } }
Runnable接口
步驟:
1>定義類實現Runnable接口。
2>覆蓋接口中的run方法。
3>經過Thread類建立線程對象;
4>將實現了Runnable接口的子類對象做爲實際參數傳遞給Thread類中的構造函數。
5>調用線程的start方法,開啓線程,並執行run方法。
Callable接口
步驟:
1>定義類實現callable接口。
2>複寫接口中的call方法。
3>建立FutureTask對象,而且將實現了callable做爲對象傳入
4> 將FutureTask對象做爲實際參數傳遞給Thread類中的構造函數
5>調用線程的start方法,開啓線程,並執行call方法
備註:Callable具備返回值,但仍是相應的FutureTask的get方法是一個阻塞式的方法,須要獲取在start以後有值,假如在start以前書寫get方法,那麼一直會處於阻塞狀態,當咱們在線程池中使用的是FutureTask對象,那麼submit後的引用的get方法取不到值,但能夠用FutureTask對象的get方法去獲得值,只有使用callable的submit後的引用的get方法能取到值
//jion方法
public class ThreadTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ThreadTestA threadTestA = new ThreadTestA(); threadTestA.setName("A"); threadTestA.start(); Thread threadB = new Thread(new ThreadTestB(), "B"); threadB.start(); FutureTask<String> futureTask = new FutureTask<>(new ThreadTestC()); Thread threadC = new Thread(futureTask, "C"); threadC.start(); String string = futureTask.get(); System.out.println(string); } } class ThreadTestA extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + ":hello thread"); } } class ThreadTestB implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + ":hello runnable"); } } class ThreadTestC implements Callable<String> { @Override public String call() throws Exception { return Thread.currentThread().getName() + ":HELLO CALLABLE"; } }
//sleep和wait的區別
//sleep 不會釋放鎖,也不會釋放線程 處於阻塞狀態
//wait 會釋放鎖,不會釋放線程,處於阻塞狀態
public class SleepAndWait { public static void main(String[] args) throws InterruptedException { SleepTest sleepTest = new SleepTest(); CountDownLatch countDownLatch = new CountDownLatch(2); long start = System.currentTimeMillis(); for (int i = 0; i < 2; i++) { new Thread(new Runnable() { public void run() { try { sleepTest.testA(); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println(end - start);// 4001 WaitTest waitTest = new WaitTest(); CountDownLatch countDownLatch1 = new CountDownLatch(2); start = System.currentTimeMillis(); for (int i = 0; i < 2; i++) { new Thread(new Runnable() { public void run() { try { System.out.println(Thread.currentThread().getName() + ":hello"); // 回到阻塞狀態 waitTest.testA(); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch1.countDown(); } }).start(); } countDownLatch.await(); end = System.currentTimeMillis(); System.out.println(end - start);// 4001 } } class SleepTest { public synchronized void testA() throws InterruptedException { Thread.sleep(1000); ; } } class WaitTest { public synchronized void testA() throws InterruptedException { this.wait(); } }
//yield會放棄線程,而後調用優先級較高的,但這個方法不是絕對可行的,只是機率型事件
//相應的也會將相應的位置放入棧中,下次調度的時候回到相應的位置
public static void main(String[] args) { A a = new A(); Thread threadA = new Thread(a,";程A"); B b = new B(); Thread threadB = new Thread(b,";程B"); threadA.start(); threadB.start(); } } class A implements Runnable{ @Override public void run() { System.out.println(1); Thread.yield(); System.out.println(2); } } class B implements Runnable{ @Override public void run() { System.out.println(3); Thread.yield(); System.out.println(4); } }//可能會調用到本身 3 4 1 2的出現
7.線程池基本使用
7.1向線程池中添加線程,需實現了callable接口或者runnable接口
線程池的體系結構:
java.util.concurrent.Executor : 負責線程的使用與調度的根接口
ExecutorService : 線程池的主要接口
ThreadPoolExecutor 線程池的實現類
ScheduledExecutorService :負責線程的調度
ScheduledThreadPoolExecutor :繼承 ThreadPoolExecutor, 實現 ScheduledExecutorService
7.2工具類:Executors
ExecutorService newFixedThreadPool() : 建立固定大小的線程池
ExecutorService newCachedThreadPool() : 緩存線程池,線程池的數量不固定,能夠根據需求自動的更改數量。
ExecutorService newSingleThreadExecutor() : 建立單個線程池。線程池中只有一個線程
ScheduledExecutorService newScheduledThreadPool() : 建立固定大小的線程,能夠延遲或定時的執行任務。
備註一下:api方法前帶new表示新建的對象,不帶new表示原對象
public class ThreadTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);//建立固定的線程池 newFixedThreadPool.submit(new ThreadTestA()); newFixedThreadPool.submit(new ThreadTestB()); Future<String> submit = newFixedThreadPool.submit(new ThreadTestC()); String string2 = submit.get(); System.out.println(string2); newFixedThreadPool.shutdown();//線程執行完成後關閉,不在接受新的任務 shutdownNow試圖關閉全部正在執行的任務 ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(5); //每一個10s執行一次,初始在1s後執行 newScheduledThreadPool.scheduleWithFixedDelay(new ThreadTestA(), 1, 10, TimeUnit.SECONDS); //一秒後執行執行一次 newScheduledThreadPool.schedule(new ThreadTestB(), 1, TimeUnit.SECONDS);
newFixedThreadPool.shutdown();
newScheduledThreadPool.shutdown();
} } class ThreadTestA extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + ":hello thread"); } } class ThreadTestB implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + ":hello runnable"); } } class ThreadTestC implements Callable<String> { @Override public String call() throws Exception { return Thread.currentThread().getName() + ":HELLO CALLABLE"; } }
8.線程池的基本原理
1)線程池判斷核心線程池裏的線程是否都在執行任務。若是沒有則建立核心線程去執行任務,若是核心線程池裏的線程都在執行任務;而後線程池判斷工做隊列是否已經滿。若是工做隊列沒有滿,則將新提交的任務存儲在這個工做隊列裏。若是工做隊列滿了,而後線程池判斷線程池的最大的線程數是否都處於工做狀態。若是沒有,則建立一個新的工做線程來執行任務。線程超出 maximumPoolSize,在這種狀況下,任務將被拒絕;而後多於 corePoolSize 的線程,則這些多出的線程在空閒時間超過 keepAliveTime 時將會終止.
線程池的底層實現:
volatile int runState; static final int RUNNING = 0; static final int SHUTDOWN = 1; static final int STOP = 2; static final int TERMINATED = 3;
當線程數小於核心線程數的時候,以下會建立一個線程去執行,建立後處於死循環狀態
private boolean addIfUnderCorePoolSize(Runnable firstTask) { Thread t = null; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { if (poolSize < corePoolSize && runState == RUNNING) t = addThread(firstTask); //建立線程去執行firstTask任務 } finally { mainLock.unlock(); } if (t == null) return false; t.start(); return true; }
當大於核心線程數而阻塞隊列沒有滿時,死循環的線程不斷從阻塞隊列中獲取任務
public void run() { try { Runnable task = firstTask; firstTask = null; while (task != null || (task = getTask()) != null) { runTask(task); task = null; } } finally { workerDone(this); } }
Runnable getTask() { for (;;) { try { int state = runState; if (state > SHUTDOWN) return null; Runnable r; if (state == SHUTDOWN) // Help drain queue r = workQueue.poll(); else if (poolSize > corePoolSize || allowCoreThreadTimeOut) //若是線程數大於核心池大小或者容許爲核心池線程設置空閒時間, //則經過poll取任務,若等待必定的時間取不到任務,則返回null r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS); else r = workQueue.take(); if (r != null) return r; if (workerCanExit()) { //若是沒取到任務,即r爲null,則判斷當前的worker是否能夠退出 if (runState >= SHUTDOWN) // Wake up others interruptIdleWorkers(); //中斷處於空閒狀態的worker return null; } // Else retry } catch (InterruptedException ie) { // On interruption, re-check runState } } }
若是線程池處於STOP狀態、或者任務隊列已爲空或者設置allowCoreThreadTimeout爲true時(核心線程也退出,假如設置爲false,默認爲false,核心線程數通常不會關閉),而且線程數大於1時,容許worker退出。若是容許worker退出,則調用interruptIdleWorkers()中斷處於空閒狀態的worker
void interruptIdleWorkers() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) //實際上調用的是worker的interruptIfIdle()方法 w.interruptIfIdle(); } finally { mainLock.unlock(); } }
void interruptIfIdle() { final ReentrantLock runLock = this.runLock; if (runLock.tryLock()) { //注意這裏,是調用tryLock()來獲取鎖的,由於若是當前worker正在執行任務,鎖已經被獲取了,是沒法獲取到鎖的 //若是成功獲取了鎖,說明當前worker處於空閒狀態 try { if (thread != Thread.currentThread()) thread.interrupt(); } finally { runLock.unlock(); } } }
備註:也就是說能添加的最大的任務數是最大的線程數+BlockingQueue工做隊列
2)被拒絕執行任務時的策略
ThreadPoolExecutor.AbortPolicy 丟棄任務,並拋出 RejectedExecutionException 異常。
ThreadPoolExecutor.CallerRunsPolicy:該任務被線程池拒絕,由調用 execute方法的線程執行該任務。
ThreadPoolExecutor.DiscardOldestPolicy : 拋棄隊列最前面的任務,而後從新嘗試執行任務。
ThreadPoolExecutor.DiscardPolicy,丟棄任務,不過也不拋出異常。
3)線程池都是經過 ThreadPoolExecutor這個核心類來建立的,咱們自定義線程池也能夠用這個類來實現,最終是經過ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)來實現的,在newFixedThreadPool和newSingleThreadExecutor以及newCachedThreadPool都是使用的默認的RejectedExecutionHandler defaultHandler =new AbortPolicy()策略。
4)自定義線程池
public class MyExcutorsTest { public static void main(String[] args) { // ThreadPoolExecutor(int corePoolSize, 核心線程數 // int maximumPoolSize, 最大線程數 // long keepAliveTime, 超過核心線程數小於最大線程數的保持空閒時間 // TimeUnit unit, 時間單位 // BlockingQueue<Runnable> workQueue, 阻塞隊列 // ThreadFactory threadFactory, 線程工廠 // RejectedExecutionHandler handler) 被拒絕執行任務時的策略 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 2, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), Executors.defaultThreadFactory(), new AbortPolicy()); for (int i = 0; i < 6; i++) { threadPoolExecutor.submit(new MyExcutorsTest().new MyExcutorsTestA()); /* * 結果 2(最大)+3(阻塞隊列)=5大於五拋出異常 pool-1-thread-1 pool-1-thread-2 * pool-1-thread-1 pool-1-thread-2 pool-1-thread-1 * //拋出異常java.util.concurrent.RejectedExecutionException異常 */ } threadPoolExecutor.shutdown(); } class MyExcutorsTestA implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
9.BlockingQueue:阻塞隊列,實現是線程安全的
1)定義:支持阻塞的插入方法:當阻塞隊列已滿時,隊列會阻塞插入元素的線程,直到隊列不滿;支持阻塞的移除方法:隊列爲空時,獲取元素的線程會等待隊列變爲非空。相似於一個生產者和消費者模式,生產者相似於插入,消費者相似於移除,而隊列就是倉庫
2)對於隊列已滿時繼續插入具備4種策略
拋出異常:當隊列滿時,若是再往隊列裏插入元素,會拋出IllegalStateException("Queuefull")異常。當隊列空時,從隊列裏獲取元素會拋出NoSuchElementException異常。add,remove,element方法
返回特殊值:當往隊列插入元素時,會返回元素是否插入成功,成功返回true。若是是移除方法,則是從隊列裏取出一個元素,若是沒有則返回null。offer poll peek 方法
一直阻塞:當阻塞隊列滿時,若是生產者線程往隊列裏put元素,隊列會一直阻塞生產者線程,直到隊列可用或者響應中斷退出。當隊列空時,若是消費者線程從隊列裏take元素,隊列會阻塞住消費者線程,直到隊列不爲空。 put take
超時退出:當阻塞隊列滿時,若是生產者線程往隊列裏插入元素,隊列會阻塞生產者線程一段時間,若是超過了指定的時間,生產者線程就會退出。 offer poll方法
備註:若是是無界阻塞隊列,隊列不可能會出現滿的狀況,因此使用put或offer方法永遠不會被阻塞,並且使用offer方法時,該方法永遠返回true。
3)java中提供了7個阻塞隊列
ArrayBlockingQueue:一個由數組結構組成的有界阻塞隊列。按照先進先出(FIFO)的原則對元素進行排序。在默認插入隊列時並不保證公平性,能夠設置
LinkedBlockingQueue:一個由鏈表結構組成的有界阻塞隊列則,默認值是 Integer.MAX_VALUE,(newFixedThreadPool和newSingleThreadExecutor使用的就是這種隊列),此隊列按照先進先出的原則對元素進行排序
PriorityBlockingQueue:一個支持優先級排序的無界阻塞隊列。默認狀況下元素採起天然順序升序排列
DelayQueue:一個使用優先級隊列實現的無界阻塞隊列。
SynchronousQueue:一個不存儲元素的阻塞隊列,newCachedThreadPool使用的就是這種隊列),每個put操做必須等待一個take操做,不然不能繼續添加元素,默認狀況下線程採用非公平性策略訪問隊列,使用如下構造方法能夠建立公平性訪問的SynchronousQueue,若是設置爲true,則等待的線程會採用先進先出的順序訪問隊列。
LinkedTransferQueue:一個由鏈表結構組成的無界阻塞隊列。
LinkedBlockingDeque:一個由鏈表結構組成的雙向阻塞隊列。
10.volatile與synchronized及atomic
volatile:只保證內存的可見性,並不保證原子性,synchronized的輕量級算法
synchronized:保證內存的可見性以及原子性
atomic:cas算法保證內存的可見性以及原子性
cas算法:有3個操做數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改成B,不然什麼都不作。
public class VolatileTest2 { //死循環輸出,由於while(true)的效率是很是的高的,驗證共享機制 @Test public void test() { VolatileTestC volatileTestC = new VolatileTestC(); new Thread(volatileTestC).start(); while(true){ if(VolatileTestC.flag2){ System.out.println("flag2"); break; } } } } //每一個線程本身有本身的內存,--驗證共享內存機制 class VolatileTestC implements Runnable{ public static boolean flag2; @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } flag2=true; System.out.println("flag=true"); } }
public class VolatileTest2 { //死循環輸出,由於while(true)的效率是很是的高的 @Test public void test() { VolatileTestC volatileTestC = new VolatileTestC(); new Thread(volatileTestC).start(); while(true){ if(VolatileTestC.flag2){ System.out.println("flag2"); break; } } } } //每一個線程本身有本身的內存,--驗證共享內存機制 --volatile保證內存的可見性 class VolatileTestC implements Runnable{ public static volatile boolean flag2; @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } flag2=true; System.out.println("flag=true"); } }
//volatile不能保證原子性
public class VolatileAtomicTest { public static void main(String[] args) {
VolatileAtomicTestA volatileAtomicTestA=new VolatileAtomicTestA(); for (int i = 0; i < 10; i++) { new Thread(volatileAtomicTestA).start(); } } } class VolatileAtomicTestA implements Runnable { public volatile static int i=10; @Override public void run(){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+test()); } public int test(){ return i--; } }
/*輸出
Thread-0:10
Thread-2:10
Thread-1:9
Thread-5:8
Thread-6:5
Thread-3:6
Thread-9:7
Thread-4:4
Thread-8:3
Thread-7:2
*/
public class AtomicTest { public static void main(String[] args) { AtomicTestA atomicTestA = new AtomicTestA(); for (int i = 0; i < 10; i++) { new Thread(atomicTestA).start(); } } } class AtomicTestA implements Runnable { //AtomicInteger 使用的是對象鎖 public AtomicInteger atomicInteger =new AtomicInteger (10); @Override public void run(){ System.out.println(Thread.currentThread().getName()+":"+test()); } //atomicInteger public int test(){ return atomicInteger.decrementAndGet(); } }
/*
Thread-0:8
Thread-5:4
Thread-3:9
Thread-4:5
Thread-1:7
Thread-2:6
Thread-7:2
Thread-6:3
Thread-8:1
Thread-9:0
*/
public class TestCompareAndSwap { public static void main(String[] args) { CompareAndSwap cas = new CompareAndSwap(); for (int i = 0; i < 100; i++) { new Thread(new Runnable() { @Override public void run() { int expectedValue = cas.get(); //會爭搶鎖 //假如在這裏加一個線程延時那麼會基本上是false boolean b = cas.compareAndSet(expectedValue, (int)(Math.random() * 101)); System.out.println(b); } }).start(); } } } class CompareAndSwap{ private int value; //獲取內存值 public synchronized int get(){ return value; } //比較 public synchronized int compareAndSwap(int expectedValue, int newValue){ int oldValue = value; if(oldValue == expectedValue){ this.value = newValue; } return oldValue; } //設置 public synchronized boolean compareAndSet(int expectedValue, int newValue){ return expectedValue == compareAndSwap(expectedValue, newValue); } }
public class StaticLockAndLock { public static void main(String[] args) throws InterruptedException { StaticLockAndLockTest staticLockAndLockTest = new StaticLockAndLockTest(); CountDownLatch countDownLatch = new CountDownLatch(2); long start = System.currentTimeMillis(); new Thread(new Runnable() { public void run() { try { StaticLockAndLockTest.testA(); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); } }).start(); new Thread(new Runnable() { public void run() { try { staticLockAndLockTest.testB(); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); } }).start(); countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println(end - start); } } class StaticLockAndLockTest { // 使用的鎖是字節碼--類鎖 public static synchronized void testA() throws InterruptedException { Thread.sleep(1000); System.out.println(111111111); } // 使用的鎖是對象---對象鎖 public synchronized void testB() throws InterruptedException { Thread.sleep(1000); System.out.println(222222222); } } /* * 輸出結果 111111111 * 22222222 * 1002 */
11.Lock
public class ReentrantlockTest { public static void main(String[] args) { ReentrantlockTestA reentrantlockTestA = new ReentrantlockTestA(); for (int i = 0; i < 2; i++) { new Thread(new Runnable() { public void run() { try { reentrantlockTestA.testA(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } } class ReentrantlockTestA { Lock lock = new ReentrantLock(); int i; public void testA() throws InterruptedException { lock.lock(); try { System.out.println(Thread.currentThread().getName() + ":" + i); Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + ":" + ++i); } finally { lock.unlock(); } } } /* * 輸出 * Thread-0:0 * Thread-0:1 * Thread-1:1 * Thread-1:2 */ /* * 去除lock後的輸出 * Thread-0:0 * Thread-1:0 * Thread-1:1 * Thread-0:1 */
//abc輸出
public class demo7 { public static void main(String[] args) { print print = new print(); new Thread(new Runnable() { public void run() { for (int i = 1; i <=3; i++) { print.loopA(i); } } }, "A").start(); new Thread(new Runnable() { public void run() { for (int i = 1; i <= 3; i++) { print.loopB(i); } } }, "B").start(); new Thread(new Runnable() { public void run() { for (int i = 1; i <= 3; i++) { print.loopC(i); } } }, "C").start(); } } // alternate class print { private int number = 1; private Lock lock = new ReentrantLock(); private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); public void loopA(int i) { lock.lock(); try { if (number != 1) { condition1.await(); } for (int j = 1; j <= 10; j++) { System.out.println(Thread.currentThread().getName() + "\t" + j + "\t" + i); } number = 2; condition2.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void loopB(int i) { lock.lock(); try { if (number != 2) { condition2.await(); } for (int j = 1; j <= 10; j++) { System.out.println(Thread.currentThread().getName() + "\t" + j + "\t" + i); } number = 3; condition3.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void loopC(int i) { lock.lock(); try { if (number != 3) { condition3.await(); } for (int j = 1; j <= 10; j++) { System.out.println(Thread.currentThread().getName() + "\t" + j + "\t" + i); } number = 1; condition1.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
public class ReadAndWriteLock { // 讀寫互斥 // 寫寫互斥 // 讀讀不互斥 public static void main(String[] args) { ReadAndWriteLockA readAndWriteLockA = new ReadAndWriteLockA(); new Thread(new Runnable() { public void run() { readAndWriteLockA.testWrite(); } }).start(); for (int i = 0; i < 100; i++) { new Thread(new Runnable() { public void run() { readAndWriteLockA.testRead(); } }).start(); } } } class ReadAndWriteLockA { private int i; ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public void testRead() { readWriteLock.readLock().lock(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(i); readWriteLock.readLock().unlock(); } public void testWrite() { readWriteLock.writeLock().lock(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("write"); this.i = 1; readWriteLock.writeLock().unlock(); } }
12.其餘鎖語義說明
互斥鎖:只能一個進入其餘不能夠進入,當進入失敗,就進入休眠等待休眠結束後才能去嘗試訪問
自旋鎖:只能一個進入其餘不能夠進入,當進入失敗,不停的循環去嘗試訪問
悲觀鎖:表鎖,原理見redis linux 基礎入門
樂觀鎖:行鎖,原理見redis linux 基礎入門
13.同步異步,阻塞和非阻塞
同步:我叫你某件事,你沒去,我就一直喊
異步:我叫你作某件過後我作別的事情去了,至於你有沒有作跟我無關
阻塞:我去作某事,堵車我就一直等着
非阻塞:我去作某事,堵車我就作別的事情,不堵車了再來
14.ConcurrentHashMap
分段鎖機制(16段),較hashtable效率蓋
15.死鎖,活鎖和飢餓
死鎖:一個須要資源A,一個須要資源B,拿到資源A的人須要拿資源B,不釋放A,拿到B的人須要拿資源A,不釋放B,這樣就都拿不到
活鎖:一個須要資源A,一個須要資源B,拿到資源A的人須要拿資源B而拿不到資源B,因此釋放A,拿到B的人須要拿資源A,而拿不到資源A,因此釋放B,而後發現拿到了B,另外一個拿到了A,拿到A的人結果發現拿不到B,拿到B的人結果發現拿不到A,依次循環,就是活鎖
飢餓:因爲某些緣由致使某些線程不能被調用,例如某一個線程的優先級極低,而一直不被調度