compare java wait/notify synchronization with lock or condition in java.util.concurrent (juc)

為什麼 Java 的 wait/notify 逐漸被新 API 取代?

在 Java 的演進過程中,雖然 Object.wait()Object.notify() 仍存在於核心庫中,但在現代開發場景,java.util.concurrent (JUC) 提供的 LockCondition 已成為主流。以下是三大核心取代原因:

1. 靈活性與精確控制 (Multiple Conditions)

這是最關鍵的進步。舊有機制中,每個物件僅有一個「等待集」。

  • 舊機制: 生產者與消費者共用同一個等待隊列。呼叫 notify() 無法指定喚醒誰,常被迫改用 notifyAll(),導致驚群效應 (Thundering Herd)
  • 新機制 (Condition): 一個鎖可建立多個條件物件(如 notFull, notEmpty)。生產者只需喚醒消費者,反之亦然,效能大幅提升。

2. 安全性與健壯性 (Robustness)

新 API 解決了許多語法上的僵化問題:

特性 Object.wait/notify JUC Condition
鎖的依賴 強烈耦合 synchronized 配合 ReentrantLock,更靈活
中斷響應 僅支援基本中斷 支援不可中斷的等待 (awaitUninterruptibly)
超時控制 毫秒級 精確至奈米級 (nanoseconds)

3. 功能擴展性 (Advanced Features)

ReentrantLock 提供了舊機制無法達成的進階功能:

公平性 (Fairness): 新 API 支援公平鎖設定,確保等待最久的執行緒優先獲取資源。
非阻塞嘗試: 透過 tryLock(),執行緒可以在拿不到鎖時立即返回,避免死等。
總結:除非是極簡的同步邏輯,否則在現代 Java 開發中,ReentrantLock + Condition 是更安全、高效的選擇。

choose which S3 object ownership?

S3 Object Ownership 兩種模式差異

Amazon S3 服務全名為 簡單儲存服務 (Simple Storage Service),可支援存取放置於AWS公有雲的檔案,其服務類似 Google Drive 或 Microsoft OneDrive 的網碟功能。S3 儲存容器稱為水桶,儲存的檔案稱為物件。

建立S3水桶時,須決定上傳到水桶的物件,其擁有者將自動歸屬於誰,稱為物件擁有權(Object Ownership)設定。只有物件的擁有者才能設定物件的存取權。這裡簡單介紹兩種設定模式的差異:

🔒 模式一:ACL disabled(recommended)

所有物件都由 Bucket 擁有者持有,不論是誰上傳。ACL 完全被停用,不能再用 ACL 來授權。存取控制只能透過 IAM Policy 或 Bucket Policy 來設定。

優點:集中管理,避免跨帳號物件所有權混亂。

最佳實務:AWS 建議使用這種模式,因為更安全、更容易維護。

🔑 模式二:ACLs enabled

物件可能由上傳者帳號持有,而不是 Bucket 擁有者。存取控制可以透過 ACL(物件或 Bucket 層級)來設定。Bucket Policy 仍然可以使用,但 ACL 會一起參與判斷。

用途:適合跨帳號上傳的特殊情境,例如合作夥伴需要保有自己上傳檔案的所有權。

缺點:管理較複雜,容易造成權限混亂。

⚡ 簡單比較
模式	     物件擁有者	                存取控制方式	      AWS 建議
ACL Disabled Bucket 擁有者	        Policy(IAM / Bucket)✅ 建議
ACL Enabled  上傳者帳號可能成為物件擁有者  ACL + Policy	      僅限特殊需求

✍️ 結語

如果你的環境需要簡單、集中、安全的存取管理,選擇 ACL Disabled(Bucket owner enforced) 是最佳做法。 只有在跨帳號物件所有權的特殊需求下,才需要考慮 ACL Enabled

註: S3 權限管理機制比較:ACL vs. 水桶政策

功能特性 S3 ACL (存取控制清單),舊版 水桶政策 (Bucket Policy),新版
物件所有權 預設由「上傳者」擁有物件,即使上傳者不是水桶擁有者。 由「水桶擁有者」自動擁有水桶內的所有物件。
設定格式 XML 格式。 JSON 格式。
控制粒度 可針對「單一物件」進行微調。 針對整個水桶或特定「前綴 (Prefix/資料夾)」進行管理。
權限複雜度 僅限基本權限(讀取、寫入、完全控制),不支援「拒絕 (Deny)」。 支援複雜條件(IP 限制、MFA、特定時間、明確拒絕等)。
稽核便利性 低。必須逐一檢查每個物件的 ACL 才能得知誰有存取權。 高。只需查看一個 JSON 文件即可瞭解全域權限。
AWS 建議實務 不建議使用(除了特定日誌寫入需求)。 強烈建議使用(最佳實務)。

how to deal with metric scale inconsistency in topn recommendation evaluation

🎯 推薦系統一般會回傳前 N 個排名的物品清單給用戶,稱為 Top‑N 推薦。 遇到推薦模型須要訓練及評估時,習慣先蒐集用戶與物品的互動資料,再將資料拆分成沒有重疊的訓練集及測試集。 模型在訓練時只看得到訓練集,評估時則拿測試集作為驗證的標準答案,以免作弊。

通常,在評估推薦模型時,和一般機器學習的模型評估不同,會採用逐用戶等比例切割 (userwise stratified split) 評估法。 即針對每個用戶的喜好物品,等比例拆分成訓練集及測試集,請模型利用全體訓練集作出該用戶的 Top‑N 推薦,然後利用其個人測試集作核對,計算該用戶的得分指標。 因為模型未看過測試集,所以最後全體用戶的指標平均值就是模型的客觀表現,可供比較之用。

上述作法在實際計算得分指標時,常遇到測試集數量和推薦數量 N 不匹配,造成得分指標尺規不一致的困擾。以下進行問題,原理,及解法說明。

❓ 問題介紹

逐用戶等比例切割 的設定下,每位用戶的測試集互動數量不一樣。 當使用固定的 Top‑N 推薦清單做評估時,就會出現「測試集大小與 Top‑N 回傳數量不匹配」的情況:

  • 👤 輕度互動的用戶:測試集互動數 |Rᵤ| < N
  • 👥 重度互動的用戶:測試集互動數 |Rᵤ| > N

這會讓 回傳數量 N 的精確率 Precision@N,及回傳數量 N 的召回率 Recall@N 產生尺規上限受限的現象, 影響不同用戶之間評比的尺規公平性。

🔍 原理說明(為什麼會不公平)

若使用 Top‑N 評估,指標的分母固定或依用戶而變:

  • Precision@N = 命中數 / N,其分母固定為 N, 輕度互動用戶的精確率最大值會受此尺規「天花板」限制,達不到 1.0。
  • Recall@N = 命中數 / |Rᵤ|,其分母為 |Rᵤ|, 重度互動用戶的召回率最大值會受此尺規「天花板」限制,達不到 1.0。

這並非「計算錯誤」,而是 Top‑N 回傳量的本質所導致的評估上限不一致。

相比之下,✨正規化打折累積增益 NDCG@N 指標會以用戶理想排序的 理想打折累積增益 IDCG 進行正規化, 而 IDCG 的長度是 min(|Rᵤ|, N)。因此每位用戶都能達到 1.0 的尺規滿分, 不會因為測試集大小不同而被系統性壓低。

💡 實務解法

以下是最常見的三種解決做法:

  1. ✅ 接受個別用戶的指標尺規上限不同:只要所有模型都在相同的尺規限制下比較,排名仍有參考價值。 因為各模型可在相同受限指標尺規範圍內求好表現,所以不影響依據指標平均值所作的模型排名比較。
  2. 📋 粗糙解法:改用留1筆 Leave‑One‑Out(LOO)分割法,每位用戶只保留一筆測試互動,再搭配 命中率 Hit Rate (HR@N) = 命中數 指標作評估, 其值為 0 或 1。
  3. ⭐ 精細解法:改以 NDCG@N 作為主指標,並輔以 Precision/Recall/HR, 讓輕重度互動的用戶都能公平比較。

start versus restart for docker containers

Docker start vs restart:快速掌握差異

Docker 是個方便的服務部署工具,可快速安裝執行伺服軟體,供瀏覽器等前台使用。當用戶從 docker 映像檔建立 (create) 及啟動 (start) 容器時,容器將分別處於 巳建立 (created)執行 (running) 狀態。然後,遇到執行意外出錯 或 管理者故意下停止指令 (docker stop) 時,容器將進入退出 (exited) 狀態。

處於退出狀態的容器,因行程退出,將喪失記憶體狀態,但仍保有原來的可寫層 (writable layer) ,即儲存體狀態。此時,兩種指令 docker start 與 docker restart 都能讓既有容器,從現有可寫層狀態,再跑起來,效果完全一樣。以下用表格整理說明兩指令適用時機之差異。

1. 指令行為比較

指令 行為說明 適用狀態
docker start 啟動 巳建立 (created)退出 (exited) 的既有容器,直接執行其進入點命令 (entrypoint command) created / exited
docker restart 同上,但遇到執行狀態的容器會先讓其 stop,再 start created / running / exited

2. 執行期影響比較

項目 start restart
送 SIGTERM / SIGKILL
PID 改變
記憶體狀態重置
中斷連線
停機時間短暫

3. docker restart 的清理範圍

區域 是否清理
In-memory data
Processes / threads
Open sockets
TCP connections
Writable filesystem
Volumes
Env / config
Image

4. 結論:適用性與效果

docker startdocker restart 兩個指令目的都在不放棄既有容器的可寫層之下,以新記憶體,執行容器的服務。在容器處於 退出 狀態時,兩者效果完全相同,都會重新啟動容器主行程,重新分配記憶體,並執行 entrypoint command。 其適用時機摘要如下表。

適用情境 效果
容器正常退出,要再跑一次docker start
就現有可寫層,啟動既有容器
程式卡住、連線異常docker restart
保留可寫層,重新啟動既有容器
組態設定或資料壞掉docker run
放棄可寫層,重新建立啟動新容器

compare java wait/notify synchronization with lock or condition in java.util.concurrent (juc)

為什麼 Java 的 wait/notify 逐漸被新 API 取代? 在 Java 的演進過程中,雖然 Object.wait() 與 Object.notify() 仍存在於核心庫中,但在現代開發場景, ...

總網頁瀏覽量