NotesThread:在 Domino 開背景執行緒的規矩——每條 thread 要 init、要自己的 session

NotesThread:在 Domino 開背景執行緒的規矩——每條 thread 要 init、要自己的 session

2026.09.30 約 860 字

你在 Java 裡想開一條背景執行緒,去跑一段會呼叫 Domino local API 的程式——直接 new Thread(...) 跑起來,卻拿不到 Notes 的執行環境、一呼叫 lotus.domino 就出事。

原因是:對 Domino local 呼叫來說,執行緒不是隨便一條 java.lang.Thread 都行——它得先被 Notes 初始化過。這件事由 NotesThread 負責。這篇講清楚 NotesThread 的三種寫法、頭尾初始化的配對規則,以及「每條 thread 一個自己的 Session」這條鐵律。


重點摘要

  • 為什麼要 NotesThread:官方明講它「extends java.lang.Thread to include special initialization and termination code for Notes/Domino」,而且「This extension to Thread is required to run Java programs that make local calls to the Notes/Domino classes」。一般 Thread 沒被 Notes init 過,local 呼叫會失敗。
  • 三種寫法:① 繼承 NotesThread、覆寫 runNotes();② 實作 Runnable 交給 NotesThread;③ 自己呼叫 static 的 sinitThread()/stermThread()。
  • 配對鐵律:stermThread() 對每個 sinitThread() 只能呼叫一次,官方建議把 stermThread 放 finally。
  • 每條 thread 一個 Session:每條做 local 呼叫的執行緒都要自己 init、並用 NotesFactory.createSession() 建自己的 Session;Session 與 Domino 物件不能跨執行緒共用。
  • 背景執行緒沒有 faces context:所以拿不到 XPages 的 sessionAsSigner——背景 thread 只能 createSession()/createSessionWithFullAccess() 自建 session。

為什麼一般 Thread 不行

官方 NotesThread (Java) 講得很直接:

The NotesThread class extends java.lang.Thread to include special initialization and termination code for Notes/Domino. This extension to Thread is required to run Java programs that make local calls to the Notes/Domino classes.

而 Running a Java program 補上鐵律:「Each thread of an application making local calls must initialize a NotesThread object.」——每一條要做 local 呼叫的執行緒,都得先初始化。沒 init 就呼叫 lotus.domino 類別,就是拿不到執行環境。

三種寫法

① 繼承 NotesThread、覆寫 runNotes()——進入點不是 run() 而是 runNotes():

public class MyJob extends NotesThread {
public void runNotes() {
try {
Session s = NotesFactory.createSession();
// …用 s 做事…
} catch (NotesException e) { e.printStackTrace(); }
}
}
new MyJob().start();

② 實作 Runnable、交給 NotesThread——照一般 threading 寫 run(),包進 NotesThread。

③ 自己呼叫 static sinitThread()/stermThread()——當你的執行緒無法繼承 NotesThread(例如 listener thread)時用這招。官方:「Listener threads must use the static methods because they cannot inherit from NotesThread.」

NotesThread.sinitThread();
try {
Session s = NotesFactory.createSession();
// …用 s 做事…
} finally {
NotesThread.stermThread(); // 每個 sinitThread 對應剛好一次
}

配對鐵律:sinitThread ↔ stermThread

用 static 那套時最容易出錯的是沒配對。官方原話:

Call stermThread() exactly one time for each call to sinitThread(); putting stermThread in a finally block is recommended.

漏了 stermThread、或呼叫次數對不上,執行緒的 Notes 資源就收不乾淨——放 finally 是官方建議的保險寫法。

每條 thread 一個 Session,別跨緒共用

這條跟 Java 端要 recycle 是同一種紀律:每條執行緒有自己的 init、自己的 Session(用 NotesFactory.createSession() 建,細節見 Java Session 與 NotesFactory 那篇)。不要把一個 Session、Database 或 Document 建在 A 執行緒、拿去 B 執行緒用——backend 物件綁著建立它的執行緒的 Notes 環境,跨緒共用會 crash 或壞資料。要在多條 thread 做事,就各自建、各自 recycle、各自 term。

背景執行緒拿不到 sessionAsSigner

一個實務現實:XPages 裡的 sessionAsSigner(見 sessionAsSigner 那篇)是綁在 faces 執行環境上的。你另開一條 NotesThread 背景執行緒時,那條 thread 沒有 faces context,拿不到 sessionAsSigner。背景工作只能用 NotesFactory.createSession()(當前 effective id/伺服器身分)或 createSessionWithFullAccess() 自建 session——想在背景以某人身分跑,得自己把需要的資訊(如目標 DB、要處理的 UNID)傳進去,不能指望 XPages 的簽章者 session。

同類別在其他語言

NotesThread 是 Java 專屬的問題:

  • LotusScript:LS agent 是單執行緒執行模型,沒有「自己開 thread」這回事,自然也沒有 NotesThread/init 的負擔。要並行,靠的是排多支 agent 或 server 的排程,不是語言內開執行緒。
  • SSJS/XPages:同樣沒有讓你手動開 Notes 執行緒的機制;要背景處理,走的是 Java(用 NotesThread)或 server 端 agent,不是 SSJS 自己開 thread。

參考來源

← 回到文章列表