netty Recycler(三) 多執行緒回收物件時競爭機制的解決
假設執行緒1建立了大量物件,執行緒2和執行緒3同時回收執行緒1的物件,當這兩個執行緒第一次回收物件時會建立WeakOrderQueue,並將其新增到執行緒1的Stack。多個執行緒操控一個Stack,這就造成了競爭。那麼netty是如何解決競爭?
程式碼
package study.recycler.again;
import io.netty.util.Recycler;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* 斷點2 主執行緒回收池中會有大量CyclerA
*/
public class CycliMutiThread7 {
private static final Recycler<CyclerA> CyclerRecyclerA = new Recycler<CyclerA>() {
@Override
protected CyclerA newObject(Handle<CyclerA> handle) {
return new CyclerA(handle);
}
};
static final class CyclerA {
private String value;
public void setValue(String value) {
this.value = value;
}
private Recycler.Handle<CyclerA> handle;
public CyclerA(Recycler.Handle<CyclerA> handle) {
this.handle = handle;
}
public void recycle() {
handle.recycle(this);
}
}
private static final Recycler<CyclerB> CyclerRecyclerB = new Recycler<CyclerB>() {
@Override
protected CyclerB newObject(Handle<CyclerB> handle) {
return new CyclerB(handle);
}
};
static final class CyclerB {
private String value;
public void setValue(String value) {
this.value = value;
}
private Recycler.Handle<CyclerB> handle;
public CyclerB(Recycler.Handle<CyclerB> handle) {
this.handle = handle;
}
public void recycle() {
handle.recycle(this);
}
}
private static final Recycler<CyclerC> CyclerRecyclerC = new Recycler<CyclerC>() {
@Override
protected CyclerC newObject(Handle<CyclerC> handle) {
return new CyclerC(handle);
}
};
static final class CyclerC {
private String value;
public void setValue(String value) {
this.value = value;
}
private Recycler.Handle<CyclerC> handle;
public CyclerC(Recycler.Handle<CyclerC> handle) {
this.handle = handle;
}
public void recycle() {
handle.recycle(this);
}
}
public static void main(String[] args) throws InterruptedException {
ConcurrentLinkedQueue<CyclerA> qAThread = new ConcurrentLinkedQueue();
Thread t = Thread.currentThread();
for (int i = 0; i < 901; ++i) {
qAThread.add(CyclerRecyclerA.get());
}
Thread t1 = new Thread(() -> {
Thread temp = t;
CyclerA cyclerA = qAThread.poll();
cyclerA.setValue("t1");
cyclerA.recycle();
});
t1.start();
t1.join();
Thread t2 = new Thread(() -> {
Thread temp = t;
CyclerA cyclerA = qAThread.poll();
cyclerA.setValue("t2");
cyclerA.recycle();
});
t2.start();
t2.join();
System.out.println("over");//斷點2
}
}
呼叫堆疊
setHead:528, Recycler$Stack (io.netty.util)
newQueue:358, Recycler$WeakOrderQueue (io.netty.util)
newWeakOrderQueue:705, Recycler$Stack (io.netty.util)
pushLater:688, Recycler$Stack (io.netty.util)
push:647, Recycler$Stack (io.netty.util)
recycle:236, Recycler$DefaultHandle (io.netty.util)
recycle:27, CycliMutiThread7$CyclerA (study.recycler.again)
lambda$main$0:80, CycliMutiThread7 (study.recycler.again)
run:-1, 440434003 (study.recycler.again.CycliMutiThread7$$Lambda$1)
run:748, Thread (java.lang)
關鍵程式碼
// Marked as synchronized to ensure this is serialized.
synchronized void setHead(WeakOrderQueue queue) {
queue.setNext(head);
head = queue;
}
由上面程式碼可以知道,netty中通過synchronized
保證多執行緒安全
此外Recycler
中還有Stack
中還有兩個函式對理解整個流程(建立新的WeakOrderQueue
並將其新增到Stack
中)比較重要,下面會按照呼叫順序講解
private void pushLater(DefaultHandle<?> item, Thread thread) {
if (maxDelayedQueues == 0) {
// We don't support recycling across threads and should just drop the item on the floor.
return;
}
// we don't want to have a ref to the queue as the value in our weak map
// so we null it out; to ensure there are no races with restoring it later
// we impose a memory ordering here (no-op on x86)
Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();
WeakOrderQueue queue = delayedRecycled.get(this);
if (queue == null) {
if (delayedRecycled.size() >= maxDelayedQueues) {
// Add a dummy queue so we know we should drop the object
delayedRecycled.put(this, WeakOrderQueue.DUMMY);
return;
}
// Check if we already reached the maximum number of delayed queues and if we can allocate at all.
if ((queue = newWeakOrderQueue(thread)) == null) {
// drop object
return;
}
delayedRecycled.put(this, queue);
} else if (queue == WeakOrderQueue.DUMMY) {
// drop object
return;
}
queue.add(item);
}
比如執行緒2回收執行緒1建立的物件,首先會通過物件中註冊的DefaultHandler
獲取物件所屬的Stack
,然後經過一系列判斷進入到pushLater
這個函式中並進行下面操作。
執行緒2第一次回收執行緒1所建立的物件
1、呼叫DELAYED_RECYCLED.get()
獲取一個ThreadLocal物件(如果沒有就建立新的)
2、呼叫newWeakOrderQueue(thread)
建立並新增WeakOrderQueue
跟蹤newWeakOrderQueue
的程式碼,可以看到WeakOrderQueue
的這個函式
static WeakOrderQueue newQueue(Stack<?> stack, Thread thread) {
// We allocated a Link so reserve the space
if (!Head.reserveSpaceForLink(stack.availableSharedCapacity)) {
return null;
}
final WeakOrderQueue queue = new WeakOrderQueue(stack, thread);
// Done outside of the constructor to ensure WeakOrderQueue.this does not escape the constructor and so
// may be accessed while its still constructed.
stack.setHead(queue);//上文提到過這個函式,用synchronized修飾過
return queue;
}
1、new WeakOrderQueue(stack, thread)
建立新的WeakOrderQueue
。其中入參thread
會存放到WeakOrderQueue.referent
中
2、上文提到過這個函式,WeakOrderQueue
放入Stack中。這個函式用synchronized
修飾過,以保證多執行緒安全。
相關文章
- 解決多執行緒競爭條件——臨界區執行緒
- 多執行緒之間的競爭執行緒
- 多執行緒下解決資源競爭的7種方法執行緒
- netty Recycler物件池Netty物件
- 大話Android多執行緒(三) 執行緒間的通訊機制之HandlerAndroid執行緒
- 執行緒池中多餘的執行緒是如何回收的?執行緒
- 多執行緒之等待通知機制執行緒
- JAVA多執行緒與鎖機制Java執行緒
- 解析Java的多執行緒機制(2)(轉)Java執行緒
- 解析Java的多執行緒機制(1)(轉)Java執行緒
- 深入理解多執行緒(三)—— Java的物件頭執行緒Java物件
- Netty原始碼死磕一(netty執行緒模型及EventLoop機制)Netty原始碼執行緒模型OOP
- java多執行緒系列之future機制Java執行緒
- Java多執行緒4:synchronized鎖機制Java執行緒synchronized
- Java多執行緒17:中斷機制Java執行緒
- 多執行緒(三)執行緒
- Java多執行緒之三volatile與等待通知機制示例Java執行緒
- C#中的執行緒(三)多執行緒C#執行緒
- 多執行緒併發執行及解決方法執行緒
- 執行緒同步機制執行緒
- 【java 多執行緒】多執行緒併發同步問題及解決方法Java執行緒
- quartz的執行緒池機制quartz執行緒
- 多執行緒系列(三):執行緒池基礎執行緒
- JavaScript執行緒機制與事件機制JavaScript執行緒事件
- Android多執行緒基礎 解析Handler機制Android執行緒
- 報警機制如何用多執行緒實現執行緒
- 淺析Java多執行緒程式設計機制Java執行緒程式設計
- java多執行緒:執行緒體往外丟擲異常的處理機制實踐Java執行緒
- Java多執行緒——獲取多個執行緒任務執行完的時間Java執行緒
- iOS多執行緒全套:執行緒生命週期,多執行緒的四種解決方案,執行緒安全問題,GCD的使用,NSOperation的使用iOS執行緒GC
- Java高階-解析Java中的多執行緒機制(轉)Java執行緒
- Java多執行緒(三):SynchronizedJava執行緒synchronized
- 多執行緒筆記 三執行緒筆記
- 解決POI多執行緒匯出時資料錯亂問題執行緒
- 多執行緒的安全問題及解決方案執行緒
- Netty執行緒模型Netty執行緒模型
- 執行緒間的協作機制執行緒
- 詳解多執行緒執行緒