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 "提供成功!";};