

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Lambda 受管執行個體的 Java 執行期
<a name="lambda-managed-instances-java-runtime"></a>

對於 Java 執行期，Lambda 受管執行個體會使用作業系統執行緒來並行。Lambda 會在初始化期間為每個執行環境載入您的處理常式物件一次，然後建立多個執行緒。這些執行緒會平行執行，並且需要安全處理狀態和共用資源的執行緒。每個執行緒共用相同的處理常式物件和任何靜態欄位。

## 並行組態
<a name="lambda-managed-instances-java-concurrency-config"></a>

Lambda 傳送至每個執行環境的並行請求數目上限是由函數組態中的 `PerExecutionEnvironmentMaxConcurrency`設定所控制。這是選用設定，預設值會根據執行時間而有所不同。對於 Java 執行時間，預設值為每個 vCPU 32 個並行請求，或者您可以設定自己的值。此值也會決定 Java 執行時間使用的執行緒數目。Lambda 會根據每個執行環境的容量，自動調整並行請求的數量，直到設定的最大值為止，以吸收這些請求。

## 為多並行建置函數
<a name="lambda-managed-instances-java-building"></a>

使用 Lambda 受管執行個體時，您應該套用與任何其他多執行緒環境中相同的執行緒安全實務。由於處理常式物件會跨所有執行時間工作者執行緒共用，因此任何變動狀態都必須是執行緒安全。這包括集合、資料庫連線，以及在請求處理期間修改的任何靜態物件。

AWS SDK 用戶端是安全的執行緒，不需要特殊處理。

**範例：資料庫連線集區**

下列程式碼使用在執行緒之間共用的靜態資料庫連線物件。視使用的連線程式庫而定，這可能不安全執行緒。

```
public class DBQueryHandler implements RequestHandler<Object, String> {
    // Single connection shared across all threads - NOT SAFE
    private static Connection connection;

    public DBQueryHandler() {
        this.connection = DriverManager.getConnection(jdbcUrl, username, password);
    }

    @Override
    public String handleRequest(Object input, Context context) {
        PreparedStatement stmt = connection.prepareStatement(query);
        ResultSet rs = stmt.executeQuery();
        // Multiple threads using same connection causes issues
        return result.toString();
    }
}
```

安全執行緒的方法是使用連線集區。在下列範例中，函數處理常式會從集區擷取連線。連線僅用於單一請求的內容。

```
public class DBQueryHandler implements RequestHandler<Object, String> {

    private static HikariDataSource dataSource;

    public DBQueryHandler() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/your_database");
        dataSource = new HikariDataSource(config); // Create pool once per Lambda container
    }

    @Override
    public String handleRequest(Object input, Context context) {
        String query = "SELECT column_name FROM your_table LIMIT 10";
        StringBuilder result = new StringBuilder("Data:\n");

        // try-with-resources automatically calls close() on the connection,
        // which returns it to the HikariCP pool (does NOT close the physical DB connection)
        try (Connection connection = dataSource.getConnection();
             PreparedStatement stmt = connection.prepareStatement(query);
             ResultSet rs = stmt.executeQuery()) {

            while (rs.next()) {
                result.append(rs.getString("column_name")).append("\n");
            }

        } catch (Exception e) {
            context.getLogger().log("Error: " + e.getMessage());
            return "Error";
        }

        return result.toString();
    }
}
```

**範例：集合**

標準 Java 集合不安全執行緒：

```
public class Handler implements RequestHandler<Object, String> {
    private static List<String> items = new ArrayList<>();
    private static Map<String, Object> cache = new HashMap<>();

    @Override
    public String handleRequest(Object input, Context context) {
        items.add("list item");  // Not thread-safe
        cache.put("key", input); // Not thread-safe
        return "Success";
    }
}
```

請改用安全執行緒集合：

```
public class Handler implements RequestHandler<Object, String> {
    private static final List<String> items = 
        Collections.synchronizedList(new ArrayList<>());
    private static final ConcurrentHashMap<String, Object> cache = 
        new ConcurrentHashMap<>();

    @Override
    public String handleRequest(Object input, Context context) {
        items.add("list item");  // Thread-safe
        cache.put("key", input); // Thread-safe
        return "Success";
    }
}
```

## 共用 /tmp 目錄
<a name="lambda-managed-instances-java-shared-tmp"></a>

`/tmp` 目錄會跨執行環境中的所有並行請求共用。同時寫入相同檔案可能會導致資料損毀，例如，如果另一個程序覆寫檔案。若要解決此問題，請實作共用檔案的檔案鎖定，或針對每個執行緒或每個請求使用唯一的檔案名稱，以避免衝突。請記得清除不需要的檔案，以避免耗盡可用空間。

## 日誌
<a name="lambda-managed-instances-java-logging"></a>

日誌交錯 （來自在日誌中交錯之不同請求的日誌項目） 在多並行系統中是正常的。

使用 Lambda 受管執行個體的函數一律使用[進階記錄控制](monitoring-logs.md#monitoring-cloudwatchlogs-advanced)所引進的結構化 JSON 日誌格式。此格式包含 `requestId`，允許日誌項目與單一請求相關聯。當您使用來自 `context.getLogger()` 的`LambdaLogger`物件`requestId`時， 會自動包含在每個日誌項目中。如需詳細資訊，請參閱 [搭配 Java 使用 Lambda 進階日誌控制項](java-logging.md#java-logging-advanced)。

## 請求內容
<a name="lambda-managed-instances-java-request-context"></a>

`context` 物件繫結至請求執行緒。使用 `context.getAwsRequestId()`可安全執行緒存取目前請求的請求 ID。

使用 `context.getXrayTraceId()` 存取 X-Ray 追蹤 ID。這可讓執行緒安全存取目前請求的追蹤 ID。Lambda 不支援具有 Lambda 受管執行個體`_X_AMZN_TRACE_ID`的環境變數。使用 AWS SDK 時，會自動傳播 X-Ray 追蹤 ID。

使用 `com.amazonaws.services.lambda.runtime.Context.getRemainingTimeInMillis()` 偵測逾時。如需詳細資訊，請參閱[錯誤處理和復原](lambda-managed-instances-execution-environment.md#lambda-managed-instances-error-handling)。

如果您在程式中使用虛擬執行緒或在初始化期間建立執行緒，您將需要將任何必要的請求內容傳遞至這些執行緒。

## 初始化和關閉
<a name="lambda-managed-instances-java-init-shutdown"></a>

每個執行環境會發生一次函數初始化。在初始化期間建立的物件會跨執行緒共用。

對於具有擴充功能的 Lambda 函數，執行環境會在關閉期間發出 SIGTERM 訊號。延伸項目使用此訊號來觸發清除任務，例如排清緩衝區。您可以訂閱 SIGTERM 事件來觸發函數清除任務，例如關閉資料庫連線。若要詳細了解執行環境生命週期，請參閱 [了解 Lambda 執行環境生命週期](lambda-runtime-environment.md)。

## 相依性版本
<a name="lambda-managed-instances-java-dependencies"></a>

Lambda 受管執行個體需要下列最低套件版本：
+ AWS 適用於 Java 的 SDK 2.0：2.34.0 版或更新版本
+ AWS 適用於 Java 的 X-Ray 開發套件：2.20.0 版或更新版本
+ AWS Distro for OpenTelemetry - 適用於 Java 的檢測：2.20.0 版或更新版本
+ 適用於 AWS Lambda (Java) 的 Powertools：2.8.0 版或更新版本

## Lambda 的 Powertools AWS (Java)
<a name="lambda-managed-instances-java-powertools"></a>

Powertools for AWS Lambda (Java) 與 Lambda 受管執行個體相容，並提供用於記錄、追蹤、指標等的公用程式。如需詳細資訊，請參閱 [Powertools for AWS Lambda (Java)](https://github.com/aws-powertools/powertools-lambda-java)。

## 後續步驟
<a name="lambda-managed-instances-java-next-steps"></a>
+ 檢閱 [Lambda 受管執行個體的 Node.js 執行期](lambda-managed-instances-nodejs-runtime.md)
+ 檢閱 [Lambda 受管執行個體的 Python 執行時間](lambda-managed-instances-python-runtime.md)
+ 檢閱 [Lambda 受管執行個體的 .NET 執行時間](lambda-managed-instances-dotnet-runtime.md)
+ 了解[擴展 Lambda 受管執行個體](lambda-managed-instances-scaling.md)