質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

12720閲覧

Thread.sleep時にInterruptedExceptionが発生してしまう。

rnosh

総合スコア171

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2019/08/01 08:23

編集2019/08/01 10:09

前提

とあるWebシステムの保守作業、あるデータ登録機能でデッドロックが発生しまして、その対処を行っています。
私が参画前の1年ほど前のリリース以降に発言した障害で、本来であればデッドロックの根本原因を突き止めてから対処したいところですが、
如何せん十数年運用されているそれなりの規模のシステムで、最近参画した私が意見したところで一蹴されるのみでした。
つまりはかなーり上の方から、対症療法でさっさと直せっていうお達しですので、「そもそもデッドロックは~」という話は今回はなしでお願いします。。。

実現したいこと

・Thread.sleep使うの初めて。。。
・所定条件を満たした際、Thread.sleep(n * 1000)で待機処理をしたい。
実装したThread.sleep(n * 1000)まで到達し、実行されていることは確認済み

バージョン

Java6

発生している問題・エラーメッセージ

java.lang.InterruptedException: sleep interrupted

該当のソースコード

■元々のソース

java

1public List<String> executeSQL(param) { 2 return executeSql; 3}

■修正後

java

1public List<String> executeSQL(param) { 2 return deadlockRetry(param); 3} 4 5// デッドロック対処メソッド 6private deadlockRetry(param) { 7 for (int retryCnt = 0; retryCnt <= maxCnt; retryCnt++) { 8 try { 9 // SQL実行 10 } catch (SQLException e) { 11 int errCode = e.getErrorCode(); 12 if (errCode == 1205) { 13 Thread.sleep(10000); 14 continue; 15 } else { 16 throw e: 17 } 18 } 19 break; 20 } 21}

試したこと、状況

・元々の作りの問題で、デッドロックの発生箇所はログから判明しているが、突合した相手のプロセスは判明していないため、強制的にデッドロックを発生させており、再現環境ではない。
→ Eclipseの表示ビューから強制的にnew SQLExceptionをスローしているがその影響はあるか?

・私自身がThreadについてあまり知見が深くない。
・調べたところ、他スレッドからの干渉があった場合に当該エラーが発生することは認識。
→ それ以上の調査結果が得られなかった・・・

・Thread.sleepの実行位置は最初に動くmainスレッドからすると4スレッド目
(main → logic → dao:SQL実行 → dao:デッドロック対処メソッド)
・デバッグで確認するも呼び出し元の上位3スレッド以外のスレッドは存在しない。

聞きたいこと

Thread.sleepが正しく発動する条件。
→ そもそもmainスレッドレベルでsleepをかけないと、呼び出し元スレッドが干渉してくることがあるのか?
→ それとも実装方法に問題あり?

Thread.sleep以外にもっとベターな待機処理があるかどうか。

不備不足あれば追記いたしますので、ご指摘いただけると幸甚です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moredeep

2019/08/01 08:55

ただの勘ですけど、daoが悪さしているんじゃないかなと。 Sleepしている間にDAOは何をしているんですかね?DAOがタイムアウト等で破棄されてなし崩し的にThreadを閉じることになってたりしませんか?
rnosh

2019/08/01 09:00

厳密にいうと、デッドロックの対処メソッドもdao内におります。 対象箇所が複数あるため、元のSQL実行メソッドは残しつつ、logicから受け取ったパラメータをそのままデッドロックの対処メソッドに渡すといった形です。 さらに言えば、元々のdaoのSQL実行メソッドは1stepのみなので、デッドロックの対処メソッドの返却値をリターンするだけのものになっています。 投稿の記載はそのように修正いたしました...
moredeep

2019/08/01 09:08

mainスレッドからすると4スレッド目とありますが、こちらも間違いでしょうか・・・? スレッドを呼び出し階層と混同して数えてしまっていたりしませんか?? どちらにせよ、Sleepしているスレッドを起動したスレッドが悪さしているという考えは継続中です。(logicですかね?)DBアクセスのタイムアウトでスレッド破棄されるというバグを最近見たので。。。
rnosh

2019/08/01 09:16

スレッドのカウントは、Eclipseデバッグ時のデバッグビューで確認した形です。 実行すると、mainスレッド・logicスレッド・dao:元のSQL実行スレッド・dao:デッドロック対処メソッドの4つになっていたので、呼び出し順的に4スレッド目と判断したのですが、、、誤りでしょうか・・・?
guest

回答2

0

ベストアンサー

Thread.sleepが正しく発動する条件。

まずInterruptedExceptionが発生する理由について正確にわかってはないですが、こちら(javaのバージョンによる違いがあるかもしれないですが、、、)にあるようにSQLのトランザクションを中止する割り込みをした後にスレッドを待ち状態にしたために起きたと思います。
逆に言えば、正しく発動する条件はThread.sleepの前かその実行中において割り込み処理をしないことになるかと思います。

Thread.sleep以外にもっとベターな待機処理があるかどうか。

すみませんがわからないです。とりあえずworkaroundだけ紹介しますが、あまり良いやり方ではないと思います。
Thread.sleep(***)の直前にThread.interrupted()を実行してください。そうすると割り込みステータスをクリアすることが出来ます。
ただ、このメソッドの本来の役割は割り込みがあったかを伝えるものであって、割り込みステータスをキャンセルさせたいものではないと思っています。ので、あまり良いやり方ではないと思っています。

以下試しに作った実装になります。

Java

1import java.util.*; 2 3public class Main { 4 public static void main(String[] args) throws Exception { 5 6 final boolean[] wait = new boolean[]{true}; 7 8 // ---- InterruptedException が呼ばれるパターン ---- 9 System.out.print("Start pattern 1.\n"); 10 11 Thread th1 = new Thread(new Runnable() { 12 @Override 13 public void run() { 14 15 // 適当に待つ 16 while(wait[0]) { 17 for(int i=0; i<1000; i++) { 18 int a = 1+1; 19 } 20 }; 21 22 try { 23 Thread.sleep(1000); 24 System.out.print("I have slept very well.\n"); 25 } catch(InterruptedException e) { 26 System.out.print("InterruptedException thrown.\n"); // <- こっちが呼ばれる 27 } 28 }; 29 }); 30 31 th1.start(); 32 33 // 適当に待つ 34 for(int i=0; i<5000; i++) { 35 int a = 1+1; 36 } 37 38 th1.interrupt(); // <- 割り込み発生 39 wait[0] = false; 40 41 th1.join(); 42 43 // ---- InterruptedException が呼ばれないパターン ---- 44 System.out.print("Start pattern 2.\n"); 45 46 wait[0] = true; 47 Thread th2 = new Thread(new Runnable() { 48 @Override 49 public void run() { 50 51 // 適当に待つ 52 while(wait[0]) { 53 for(int i=0; i<1000; i++) { 54 int a = 1+1; 55 } 56 }; 57 58 // 割り込みステータスをクリアする 59 Thread.interrupted(); 60 61 try { 62 Thread.sleep(1000); 63 System.out.print("I have slept very well.\n"); // <- 割り込みステータスをクリアしたのでこっちが呼ばれる 64 } catch(InterruptedException e) { 65 System.out.print("InterruptedException thrown.\n"); 66 } 67 }; 68 }); 69 70 th2.start(); 71 72 // 適当に待つ 73 for(int i=0; i<5000; i++) { 74 int a = 1+1; 75 } 76 77 th2.interrupt(); // <- 割り込み発生 78 wait[0] = false; 79 80 th2.join(); 81 } 82} 83 84/* Results 85================================== 86Start pattern 1. 87InterruptedException thrown. 88Start pattern 2. 89I have slept very well. 90================================== 91*/

投稿2019/08/01 17:17

shogiOtakku

総合スコア123

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rnosh

2019/08/02 04:52 編集

ご回答ありがとうございます。 > SQLのトランザクションを中止する割り込みをした後にスレッドを待ち状態にしたために起きたと思います。 このアドバイスを受けまして、Eclipse表示ビューからの強制SQLExceptionではなく、SQLを書き換えて処理の流れの中で正しくSQLExceptionを発生させ、取得変数をいじるだけで突入させたところ、InterruptedExceptionが発生することなく、スレッドが待機しました。 Eclipse表示ビューの強制実行は別スレッド判定(?)になることを学びました・・・ ありがとうございました!
guest

0

Thread.sleepがうまく動かない

とは、どうのような現象のことを指していますか?
なぜ、うまく動いていないと判断していますか?

所定条件を満たした際、Thread.sleep(n * 1000)で待機処理をしたい。

Thread.sleepが正しく発動する条件。

とくに条件はなく、Thread.sleep(10000);に到達すれば、sleepすると思いますが。
条件とは、SQLExceptionが発生して、Errcodeが1205だったらという意味ですか?

デッドロックのエラーコードは1205で合っていますか?(SQLServer?)

Thread.sleep以外にもっとベターな待機処理があるかどうか。

待機処理は、sleepでよいかと思います。


まずは、うまく動かないこと?を正しく検証してみては、どうでしょうか。
当該スレッドは、sleepのロジックを通っていますか?

投稿2019/08/01 09:50

momon-ga

総合スコア4828

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rnosh

2019/08/01 10:06

回答ありがとうございます。 少々言葉足らずでしたでしょうか、申し訳ございません。 デバッグで検証したうえで動かないので質問をした次第です。 Thread.sleepまで到達したうえで、InterruptedExceptionが発生しており、その解決法がわからなかったので。 (そもそも記載したInterruptedExceptionがThread.sleep未到達で発生するのかわかりませんが・・・) エラーコードについてはSQL Serverですので1205で間違いないと思いますが、冒頭にも記載いたしました通り、そこに関しては不問です。 故に、確実に到達したことを確認した上での質問だということを記載するよう修正いたしますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問