5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IBMメインフレームのマルチスレッドJava環境(WAS for z/OS環境)でデータセットの排他制御を実現する

Last updated at Posted at 2017-11-26

概要

JZOS[参考リンク 1]を使うと、z/OS環境(IBMメインフレーム環境)で、データセットの入出力を行うJavaプログラムを開発することができます[参考リンク 6 ]。シングル・スレッド環境で動くJavaアプリケーションであれば、データセットの排他制御はOSに任せておけば問題ありません。データセットのアロケーション時に指定するDISPパラメーター(SHR/OLD)によって下表のように排他制御されますので、アプリケーションとして特別な制御ロジックを実装する必要はありません。この場合の排他制御はプロセス間の排他制御であり、COBOL言語やPL/I言語で書かれたバッチ・プログラムをJCLで実行する際の排他制御と同じです(下記<COBOLバッチにおけるデータセットの排他制御>参照)。

新規要求\実行中処理 読み取り中(SHR) 書き込み中(OLD)
読み取り(SHR) × (注1)
書き込み(OLD) × (注1) × (注1)
注1 JCLの場合は、アクセス要求が競合すると新規要求は待ち状態になり、実行中の処理が終了してデータセットが開放されるとアクセス可能になるが、BPXWDYNによるダイナミックアロケーションの場合は即時エラーになる。なお、書き込み時にDISP=OLD、読み取り時にDISP=SHRを指定するのは、JCLで排他制御をする際の慣習であり、DISP=SHRで書き込み処理したとしても、それ自体が原因でエラーが起きるわけではない。

<COBOLバッチにおけるデータセットの排他制御>
下図のようにジョブ#1のCOBOLバッチ#1がDISP=OLDで書き込み中のデータセットに対して、ジョブ#2のCOBOLバッチ#2がDISP=OLDでアクセスを試みると、OSの排他制御により、COBOLバッチ#2はデータセットが開放されるまで待たされます。

image.png

ところが、マルチスレッド環境のJavaプログラムでは、排他制御を全てOSまかせにすることはできません。以下にマルチスレッドJava環境でデータセットを扱う際のアクセス競合関連の課題とJZOS APIによる解決方法をサンプルを交えて説明します。

マルチスレッドJava環境での課題

シングル・スレッド環境のJavaプログラムからデータセットにアクセスする場合は、競合に関して特別な対応は不要ですが、WebSphere Application Server for z/OS(以降WAS for z/OSと表記)で動くサーバー・サイドJavaアプリケーションからデータセットにアクセスする場合は考慮が必要です。WAS for z/OS環境は、マルチスレッド環境(Java EE環境)だからです。前述のOSによる排他制御は、複数プロセス間で同一データセットにアクセスする場合の話であって、同一プロセス内の複数スレッドから同一データセットにアクセスする場合は、アプリケーションの責任で排他制御ロジックを実装してデータの破壊を防ぐ必要があります(下記 <WAS for z/OS上のJavaバッチにおけるデータセット排他制御の課題> 参照)。

<WAS for z/OS上のJavaバッチにおけるデータセット排他制御の課題>
下図のJavaバッチ#1とJavaバッチ#2の排他制御は有効に機能しますが、Javaバッチ#1とJavaバッチ#3のような同一アドレス空間(Unix/Windowのプロセスに相当)内の複数スレッド間の排他制御はアプリケーションの責任で実装する必要があります。

image.png

com.ibm.jzos.Enqueueクラスで排他制御ロジックを実装

では具体的にどうすれば排他制御を実装できるかというと、これまたJZOSのAPI(com.ibm.jzos.Enqueueクラスが提供するメソッド[参考リンク 2]で実現できてしまいます。

以下にサンプル・プログラムEnqTest.javaを示します。
実装の要点を伝えるため、下記サンプルはシンプルなスタンドアロンJavaアプリケーションの形態を採っていますが、mainメソッドに記述されたロジックは、Java EEアプリケーションでもほぼそのまま使える内容です(注2)。

EnqTest.java
package sample;
import com.ibm.jzos.ZFile;
import com.ibm.jzos.Enqueue;
import javax.xml.bind.DatatypeConverter;

public class EnqTest {
	public static void main(String args[]) throws Exception {
		String qname = "TEST_Q01";
		String dsName = "USER001.TEST.DATA1";
		Enqueue enq = new Enqueue(qname, dsName);
		enq.setScope(Enqueue.ISGENQ_SCOPE_SYSTEM);
		enq.setControl(Enqueue.ISGENQ_CONTROL_SHARED);      // <- 読み込み処理の場合
		//enq.setControl(Enqueue.ISGENQ_CONTROL_EXCLUSIVE); // <- 書き込み処理の場合
		enq.setContentionActWait();
		
		try{
			enq.obtain();
			byte[] token = enq.getEnqToken();
			System.out.println("token:"+DatatypeConverter.printHexBinary(token));
			
			//ここにデータセット入出力処理を記述
			
		} catch(Throwable t) {
			t.printStackTrace();
		} finally {
			if (enq.getEnqToken() != null) {
				enq.release();
			}

		}
	}

}

ここがポイント!
以下にサンプル・プログラムのポイントを説明します。上記サンプルは排他制御にフォーカスしているため、データセットの入出力処理については割愛しています。データセットの入出力処理の具体的な内容について知りたい方は、「参考リンク 6. JZOSを使ってJavaからデータセットにアクセスしてみる」で確認していただければと思います。

  • 排他制御は、JZOS提供のcom.ibm.jzos.Enqueueクラスを利用して実装します**(注3)**。
  • コンストラクターにキュー名とリソース名を指定してEnqueueオブジェクト生成します。
  • キュー名には8文字以内の名前を指定します。
  • リソース名は1バイト~255バイトの名前を指定します。
  • Enqueue#setControlメソッドで下記いずれかのスコープを設定します。指定したスコープと上記キュー名+リソース名で排他制御対象リソースを識別し、エンキュー/デキューします**(注2)**。
  • Enqueue.ISGENQ_SCOPE_STEP アドレス・スペース内
  • Enqueue.ISGENQ_SCOPE_SYSTEM 単一システム内(デフォルト)
  • Enqueue.ISGENQ_SCOPE_SYSTEMS シスプレックス全体
  • Enqueue.ISGENQ_SCOPE_SYSSPLEX シスプレックス全体(SYSTEMSと同じ)
  • Enqueue#setControlメソッドで下記いずれかの排他制御モードを指定します。
  • Enqueue.ISGENQ_CONTROL_SHARED 共有モード(読み込み処理の場合に指定)
  • Enqueue.ISGENQ_CONTROL_EXCLUSIVE 排他モード(書き込み処理の場合に指定)
  • リソース競合発生時に待たせる場合は、Enqueue#setContentionActWaitをコールします。
  • Enqueue#obtainメソッドでエンキューします。
  • Enqueue#releaseメソッドでデキューします。

注2)
上記サンプルは、スタンドアロンJavaアプリケーションとして動かすために、スコープ指定をEnqueue.ISGENQ_SCOPE_SYSTEMにしていますが、WAS for z/OS環境で同一JVM内の複数スレッド間の競合を制御する場合は、Enqueue.ISGENQ_STEPをスコープに指定します。

注3)
APIの詳細については参考リンク2を参照してください。また、当該APIがコールするシステム・サービスについては、参考リンク3参考リンク4参考リンク5を参照してください。

参考リンク

1. JZOS Batch Launcher and Toolkit
https://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.zsecurity.80.doc/zsecurity-component/jzos.html

2. JZOS API (Javadoc)
http://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.zsecurity.api.80.doc/com.ibm.jzos/index.htm

com.ibm.jzos.EnqueueクラスのJavadoc
https://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.zsecurity.api.80.doc/com.ibm.jzos/com/ibm/jzos/Enqueue.html

3. グローバル・リソース逐次化
https://www.ibm.com/support/knowledgecenter/ja/SSLTBW_2.3.0/com.ibm.zos.v2r3.ieag400/comm.htm

4. ISGENQ — グローバル・リソース逐次化 ENQ サービス
https://www.ibm.com/support/knowledgecenter/ja/SSLTBW_2.3.0/com.ibm.zos.v2r3.ieaa900/isgenq.htm

5. ISGENQ — Global resource serialization ENQ service(上記の英文ページ)
https://www.ibm.com/support/knowledgecenter/ja/SSLTBW_2.3.0/com.ibm.zos.v2r3.ieaa200/isgenq.htm

6. JZOSを使ってJavaからデータセットにアクセスしてみる
https://qiita.com/tsunogai/items/8f75ce6a2f52c6c61ff5

5
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?