• 検索結果がありません。

ただし 無作為にスレッドを複数実行すると 結果不正やデッドロックが起きる可能性がある 複数のスレッド ( マルチスレッド ) を安全に実行する ( スレッドセーフにする ) ためには 同期処理を用いるこ とが必要になる 同期処理は 予約語 synchronized で行うことができる ここでは sy

N/A
N/A
Protected

Academic year: 2021

シェア "ただし 無作為にスレッドを複数実行すると 結果不正やデッドロックが起きる可能性がある 複数のスレッド ( マルチスレッド ) を安全に実行する ( スレッドセーフにする ) ためには 同期処理を用いるこ とが必要になる 同期処理は 予約語 synchronized で行うことができる ここでは sy"

Copied!
8
0
0

読み込み中.... (全文を見る)

全文

(1)

オブジェクト指向プログラミング演習 2010/10/27

演習課題

スレッド(その 2) 同期処理、結果不正、デッドロック

前回のスレッドの演習では、複数のスレッドを実行し、 一つのプログラムの中の違う処理を同時に実行し た。

(2)

ただし、無作為にスレッドを複数実行すると、結果不正やデッドロックが起きる可能性がある。

複数のスレッド(マルチスレッド)を安全に実行する(スレッドセーフにする)ためには、同期処理を用いる こ とが必要になる。同期処理は、予約語 synchronized で行うことができる。 ここでは、synchronized につ

(3)

課題 1

以下のプログラム Kadai101001 を複数回実行してみると、結果が違う場合がある。 /* スレッドの結果不正をテストする */

public class Kadai102701{

public static void main(String[] args){

SimpleThreadTest simpleThreadTest = new SimpleThreadTest(); Thread thread = new Thread(simpleThreadTest);

thread.start(); //simpleThreadTest.run()が呼ばれ,その後 add()を呼ぶ simpleThreadTest.add(); //同時にもう一回 add()を呼ぶ

} }

class SimpleThreadTest implements Runnable{ int sum; //合計を保持するインスタンス変数

/* Thread.start()から呼ばれる */ public void run(){

this.add(); //add()を呼ぶだけ }

/* 0 + 100 を行うだけ */ public void add(){

//sleep()でちょっと一休み。結果不正を出しやすくする。 try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException ie){} sum = 0; //sum を 0 にして //sleep()でちょっと一休み。結果不正を出しやすくする。 try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException ie){}

sum = sum + 100; // sum に 100 足す

//sleep()でちょっと一休み。結果不正を出しやすくする。 try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException ie){} System.out.println("0+100 ="+sum); //0+100 は 100 のはず? } }

(4)

実行例 メソッドを synchronized 宣言することにより、そのメソッドが複数のスレッド から同時に呼ばれないように することができる。 上記例では、メソッド dangerousMethod() を synchronized 宣言することにより、 メソッド dangerousMethod() は複数のスレッドから同時に呼ばれない。 (後に呼んだスレッドは、前のスレッドがメ ソッドを抜けるまで待つ。) プログラム Kadai102701 のメソッドに synchronized 宣言を追加し、0+100=100 と常に正しく表示される ように 修正せよ。 課題 2 synchronized はメソッド全体のロックだけでなく、 特定のブロックだけをロックすることもできる。 synchronized( オブジェクト ) { ブロック } 上記では、オブジェクトをロックし、ブロック内を安全に処理する。 別のスレッドで、同じオブジェクト(鍵)を ロックする synchronized 処理は同時に 実行されず、ブロック内の処理を完了するまで待たされる。 例) $ java Kadai102701 0+100 =100 0+100 =200 $ java Kadai102701 0+100 =200 0+100 =200 $ java Kadai102701 0+100 =0 0+100 =100 $

public synchronized void dangerousMethod(){ ...

}

synchronized( this ) { //this をロックオブジェクトに利用する例 dangerousData += 100;

... }

(5)

以下のプログラム Kadai102702 を複数回実行してみると、結果が違う場合がある。 /* スレッドの結果不正をテストする */

public class Kadai102702{

public static void main(String[] args){

SimpleThreadTest simpleThreadTest = new SimpleThreadTest(); Thread thread = new Thread(simpleThreadTest);

thread.start(); //simpleThreadTest.run()が呼ばれ,その後 add()を呼ぶ simpleThreadTest.subtract(); //同時に subtract()を呼ぶ

} }

class SimpleThreadTest implements Runnable{ int sum; //合計を保持するインスタンス変数

/* Thread.start()から呼ばれる */ public void run(){

this.add(); //add()を呼ぶだけ }

/* 0 + 100 を行うだけ */ public void add(){

//sleep()でちょっと一休み。結果不正を出しやすくする。 try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException ie){} sum = 0; //sum を 0 にして //sleep()でちょっと一休み。結果不正を出しやすくする。 try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException ie){}

sum = sum + 100; // sum に 100 足す

//sleep()でちょっと一休み。結果不正を出しやすくする。 try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException ie){} System.out.println("0+100 ="+sum); //0+100 は 100 のはず? }

(6)

実行例

プログラム Kadai102702 のメソッド add() と subtract() 両方に synchronized ブロック処理を追加し、 /* 1000 - 500 を行うだけ */

public void subtract(){

//sleep()でちょっと一休み。結果不正を出しやすくする。 try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException ie){} sum = 1000; //sum を 1000 にして //sleep()でちょっと一休み。結果不正を出しやすくする。 try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException ie){}

sum = sum - 500; // sum に 100 足す

//sleep()でちょっと一休み。結果不正を出しやすくする。 try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException ie){} System.out.println("1000-500 ="+sum); //1000-500 は 500 のはず? } } $ java Kadai102702 1000-500 =500 0+100 =600 $ java Kadai102702 1000-500 =-400 0+100 =-400 $ java Kadai102702 1000-500 =100 0+100 =100 $ java Kadai102702 0+100 =600 1000-500 =600 $

(7)

課題 3 タイピングゲームなどは、自分がタイプしている最中にも、非同期的に(同時に) コンピュータが時間を計 って動作することにより、リアルタイムな操作性を実現している。 以下のタイピングゲームをスレッド処理 を用いて非同期で実行できるよう完成させなさい。 import java.io.*; /* タイピングゲームもどき */ public class Kadai102703{

public static void main(String[] args){

Typing typing = new ******(); //Typing クラスの生成 Thread thread = ******(typing); //Thread クラスの生成

System.out.println("以下の文章を間違わずにタイプしください。"); try{

Thread.sleep(1000);

}catch(InterruptedException ie){}

String string = "Now is the time for all good men to come to the aid of their country."; System.out.println(string); ******.start(); //スレッド開始 typing.type(string); } }

(8)

class Typing implements Runnable{

Object lock = new ******(); //共通ロックオブジェクトを生成 boolean fired = false;

/* Thread.start()から呼ばれる */ public void run(){

this.timer(); //timer()を呼ぶだけ }

public void timer(){ //sleep()で時間を待つ try{ Thread.sleep(10000); }catch(InterruptedException ie){} synchronized(****){ //共通のロックオブジェクト if(fired == true) { System.out.println("あなたの勝ち!"); }else{ System.out.println("ドーン! あなたの負け!"); fired = true; } } }

public void type(String string){ String line="";

try{

BufferedReader buf=new BufferedReader(new InputStreamReader(System.in)); line = buf.readLine();

}catch(IOException ioe){}

synchronized(****){ //共通のロックオブジェクト if(line.equals(string) && (fired == false)){

System.out.print("バーン!"); fired=true; } } } }

参照

関連したドキュメント

る、関与していることに伴う、または関与することとなる重大なリスクがある、と合理的に 判断される者を特定したリストを指します 51 。Entity

本節では本研究で実際にスレッドのトレースを行うた めに用いた Linux ftrace 及び ftrace を利用する Android Systrace について説明する.. 2.1

LLVM から Haskell への変換は、各 LLVM 命令をそれと 同等な処理を行う Haskell のプログラムに変換することに より、実現される。

クチャになった.各NFは複数のNF  ServiceのAPI を提供しNFの処理を行う.UDM(Unified  Data  Management) *11 を例にとれば,UDMがNF  Service

これはつまり十進法ではなく、一進法を用いて自然数を表記するということである。とは いえ数が大きくなると見にくくなるので、.. 0, 1,

6.医療法人が就労支援事業を実施する場合には、具体的にどのよう な会計処理が必要となるのか。 答

音節の外側に解放されることがない】)。ところがこ

従って、こ こでは「嬉 しい」と「 楽しい」の 間にも差が あると考え られる。こ のような差 は語を区別 するために 決しておざ