java的多線程juc

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,依次循環,就是活鎖

飢餓:因爲某些緣由致使某些線程不能被調用,例如某一個線程的優先級極低,而一直不被調度

相關文章
相關標籤/搜索