java----JUC詳解

1.Thread.State

線程幾種狀態
New:沒有啓動的線程狀態。
RUNNABLE:正在運行的線程。
BLOCKED:阻塞狀態。
WAITING:等待狀態,一直等待。
TIMED_WAITING:超時等待,時間到了就不等了。
TERMINATED:終止狀態。

2.wait與sleep區別

1>來自不同的類
wait --> Object類
sleep --> Thread類
2>關於鎖的釋放
wait會釋放鎖
sleep不會釋放鎖
3>使用範圍不同
wait:必須用在同步代碼塊中
sleep:可以用於任何地方
4>是否需要捕獲異常
wait:不需要捕獲異常
sleep:必須捕獲異常

3.Lock與synchronized區別

1>synchronized的本質是隊列+鎖。
2>Lock是一個接口,它有如下三個實現類
ReentrantLock:可重入鎖(常用)
ReadLock:讀鎖
WriteLock:寫鎖
3>區別
3.3.1 synchronized是內置java關鍵字;Lock是一個java類。
3.3.2 synchronized無法判斷獲取鎖的狀態;Lock可以判斷是否獲到了鎖。
3.3.3 synchronized會自動釋放鎖;Lock需要手動釋放鎖,容易造成死鎖。
3.3.4 synchronized時,如果線程1獲得到鎖,發生了阻塞,那麼線程2會一直等待;Lock中的tryLock()方法會嘗試獲取鎖,不會一直等待。

4.多線程間的通信問題,經典問題:生產者與消費者問題?

4.1 老版本生產者與消費者問題。
this.wait():線程等待。
this.notify():當前線程結束,通知其他所有線程。
如上這兩個方法都來源Object類。
4.2 JUC版本生產者與消費者問題
//可重入鎖
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//等待
condition.await();
//精準的通知與喚醒
condition.signal();
4.3讀寫鎖,寫鎖又稱之爲獨佔鎖,一次只能被一個線程佔有;讀鎖稱之爲共享鎖,多個線程同時佔有。
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//寫鎖
readWriteLock.writeLock().lock();
//讀鎖
readWriteLock.readLock().lock();

5.八鎖現象

synchronized鎖的對象是方法的調用者,調用者有類與類的模板(class)兩種。
static修飾方法在類加載的時候就生成了,即class。

6.集合類安全問題

併發下經常報的錯:ConcurrentModificationException。----併發修改異常。
6.1 ArrayList線程不安全,常用如下解決方案
1>vector,即方法上加了synchronized修飾。

List<String> list = new Vector<>();  

2> Collections.synchronizedList(),即採用集合工具類對集合進行加鎖。

List<String> list = Collections.synchronizedList(new ArrayList<>());

3>JUC下解決方法: 寫入時複製一個對象出來,寫入成功後覆蓋對象。

List<String> list = new CopyOnWriteArrayList<>();

4>vector與CopyOnWriteArrayList相比:vector採用synchronized修飾,效率低;CopyOnWriteArrayList採用Lock鎖機制,效率高。
6.2 HashSet線程不安全,常用如下解決方案
1>集合工具類對集合進行加鎖。

Set<String> set = Collections.synchronizedSet(new HashSet<>());

2>JUC下解決方法:

Set<String> set = new CopyOnWriteArraySet<>();

3>HashSet的底層就是HashMap
6.3 HashMap線程不安全,常用如下解決方案
1>集合工具類對集合進行加鎖。

Map<String,String> map = Collections.synchronizedMap(new HashMap<>());

2>JUC下解決方法:

Map<String,String> map = new ConcurrentHashMap<>();

7.JUC中常用三大輔助類

1>減法計數器CountDownLatch
CountDownLatch countDownLatch = new CountDownLatch(10);
//執行減一操作
countDownLatch.countDown();
//等待計數器歸零,然後執行後續操作
countDownLatch.await();
2>加法計數器CyclicBarrier

CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{
	System.out.println("達到數字10後執行打印方法!");
});

3>信號量
Semaphore semaphore = new Semaphore(10);
//得到,信號量-1,等待被喚醒
semaphore.acquire();
//釋放,信號量+1,喚醒等待線程
semaphore.release();

8.隊列詳講

Queue包含阻塞隊列(BlockingQueue)、雙端隊列、非阻塞隊列等。
BlockingQueue包括ArrayBlockingQueue、LinkedBlockingQueue。
BlockingQueue包含四組API
1>拋出異常
BlockingQueue.add()與BlockingQueue.remove()。
2>有返回值
BlockingQueue.offer()與BlockingQueue.poll()
3>阻塞等待,會一直阻塞
BlockingQueue.put與BlockingQueue.take()
4>超時等待
BlockingQueue.put與BlockingQueue.take()
BlockingQueue.offer(存放對象,秒值,TimeUnit.SECONDS)與BlockingQueue.poll(秒值,TimeUnit.SECONDS)

9.線程池

三大方法、7大參數、4種拒絕策略。
1>三大方法
//單例線程,線程池只有一個線程

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(()->{
	System.out.println(Thread.currentThread().getName());
});

//固定線程池的大小,線程池數是固定的

ExecutorService executorService = Executors.newFixedThreadPool(20);
executorService.execute(()->{
	System.out.println("最大new出20個線程!");
});

//cache:可伸縮的線程池大小

ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(()->{
	System.out.println(Thread.currentThread().getName());
});

三大方法的本質是ThreadPoolExecutor
2>線程池七大參數

public ThreadPoolExecutor(int corePoolSize,
						  int maximumPoolSize,
						  long keepAliveTime,
						  TimeUnit unit,
						  BlockingQueue<Runnable> workQueue,
						  ThreadFactory threadFactory,
						  RejectedExecutionHandler handler) {}

corePoolSize:核心線程數
maximumPoolSize:線程池最大數
keepAliveTime:超時時間
unit:超時時間單位
workQueue:阻塞隊列
threadFactory:線程工廠
handler:拒絕策略
3>四種拒絕策略
AbortPolicy:拋出異常,默認是這個策略。
CallerRunPolicy:直接返回給主線程去處理。
DiscardPolicy:不拋出異常,程序也不處理任務,任務直接丟棄。
DiscardOldestPolicy:不會拋出異常,它會去等待下之前的任務有沒有執行完成,如果之前的完成了,那麼執行這個任務,否則直接丟掉任務。
9.1 最大線程數如何設置
分成CPU密集型與I/O密集型
1>CPU密集型,Runtime.getRuntime().availableProcessors()獲取CPU個數,可以保證CPU效率最高。
2>I/O密集型,判斷程序中消耗I/O的線程個數N,設置最大線程數爲M(N<M<2N)

10.四大函數式接口

1>lambda表達式
2>鏈式編程
3>函數式接口
4>Stream流式計算
函數式接口:只有一個方法的接口,採用@FunctionalInterface註解修飾。例如:

@FunctionalInterface
public interface Runnable {
	public abstract void run();
}

10.1 四大原生函數式接口
1>Consumer
2>Function
3>Predicate
4>Supplier
10.1.1 Function函數型接口,有一個輸入,有一個輸出

Function<Integer,String> function = new Function<Integer,String>() {
	@Override
	public String apply(Integer o) {
		return String.valueOf(o);
	}
};

說明:只要是 函數式接口 都可以採用lambda表達式簡化。簡化如下:
Function function = (str)->{ return String.valueOf(str);};
調用:function.apply("hello world");
10.1.2 Predicate斷定型接口,有一個輸入,布爾值輸出

Predicate<String> predicate = new Predicate<String>() {
	@Override
	public boolean test(String str) {
		return str.isEmpty();
	}
};

簡化如下:

Predicate<String> predicate1 = (str)->{return str.isEmpty();}; 

10.1.3 Consumer消費型接口,只有輸入,沒有返回

Consumer<String> consumer = new Consumer<String>() {
	@Override
	public void accept(String str) {
		System.out.println("消費了:"+str);
	}
};

簡化如下:

Consumer<String> consumer = (str)->{ System.out.println("消費了:"+str);};

10.1.4 Supplier提供型接口,沒有輸入,只有返回

Supplier<String> supplier = new Supplier<String>() {
	@Override
	public String get() {
		System.out.println("執行提供內容");
		return "提供成功!";
	}
};

簡化如下:

Supplier<String> supplier1 = ()->{return "提供成功!";};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章