ホームページへ戻る
 

上へ戻る
 

    Java入門  その6            by  H.Y         3月 24 15:49:25 JST 2002


1。マルチスレッド
1ー1。マルチスレッドの実装
マルチスレッドを実装するには、次の2つの方法がある。
(1) java.lang.Thread クラスを継承して、run()メソッドをオーバーライドする。
(2) Runnableインターフェイスを実装する。

1ー2。Thread クラスの継承による、マルチスレッド
1)手順
(1) Thread クラスを継承したクラスを作成する。
(2) run() メソッド内に処理を記述する。
(3) Thread クラスを継承したクラスのインスタンスを作成する。
(4) start() メソッドを呼び出す。

2)スレッドの記述
======================================
class クラス名 extend Thread {
public void run() {
処理; // run() メソッドをオーバーライドする
}
}
======================================
3)スレッドの起動
=======================================
クラス名 変数 = new クラス名();
変数.start();
=======================================
これで、このオブジェクトは、別スレッドで動作する。

次の方法でもよい。
============================
new クラス名().start();
============================

4)例
--------------- TreadSample1.java -----------------------------
class ThreadSample1{
public static void main(String args[]){
ThreadB tb = new ThreadB();
ThreadC tc = new ThreadC();
tb.start();
tc.start();

int i;
try{
for(i = 0; i < 10; i++){
System.out.println("A : " + i);
Thread.sleep(1);
}
}
catch(InterruptedException e){}
}
}

//Threadを持ったクラス
class ThreadB extends Thread{
public void run(){
int i;
try{
for(i = 0; i < 10 ; i++){
System.out.println("B : " + i);
Thread.sleep(1);
}
}
catch(InterruptedException e){}
}
}
//Threadを持ったクラス
class ThreadC extends Thread{
public void run(){
int i;
try{
for(i = 0; i < 10 ; i++){
System.out.println("C : " + i);
Thread.sleep(1);
}
}
catch(InterruptedException e){}
}
}

1ー3。Runnableインターフェイスによるマルチスレッド
アプレットなどのように、他に継承するクラスがある場合は、Threadクラスの継承による方法
では、記述しずらい。この場合は、Runnableインターフェイスを使う。
1)手順
(1)Runnable インターフェイスを実装するクラスを作成する。
(2)run() メソッド内に処理を記述する。
(3)Runnable インターフェイスを実装したクラスのインスタンスを作成する。
(4)Thread クラスのインスタンスを作成する。
(5)start() メソッドを呼び出す。
2)スレッドの記述
============================================
class クラス名 implement Runnable {
public void run(){
処理;
}
}
=============================================
3)スレッドの起動
===========================================
クラス名 変数名1 = new クラス名();
Thread 変数名2 = new Thread(変数名1);
変数名2.start();
===========================================

4)例1
-------------------- TreadSample2.java --------------------
class ThreadSample2{
public static void main(String args[]){
RunnableB rb = new RunnableB();
Thread t = new Thread(rb);
t.start();

//A
int i;
try{
for(i = 0; i < 10; i++){
System.out.println("A : " + i);
}
Thread.sleep(0);
}
catch(InterruptedException e){}
}
}

//B
class RunnableB implements Runnable{
public void run(){
int i;
try{
for(i = 0; i < 10; i++){
System.out.println("B : " + i);
Thread.sleep(0);
}
}
catch(InterruptedException e){}
}
}
5)例2
----------------- runnable.java ----------------------------
class SecondThread implements Runnable {
Thread thread;

SecondThread() {
thread = new Thread(this, "second");
System.out.println("Starting second thread");
thread.start();
}

public void run() {
try {
for(int loop_index = 0; loop_index < 10; loop_index++) {
System.out.println((Thread.currentThread()).getName()
+ " thread here...");
Thread.sleep(1000);
}
} catch (InterruptedException e) {}

System.out.println("Second thread ending.");
}
}
class runnable {
public static void main(String args[]) {
SecondThread secondthread = new SecondThread();

try {
for(int loop_index = 0; loop_index < 10; loop_index++) {
System.out.println((Thread.currentThread()).getName()
+ " thread here...");
Thread.sleep(1000);
}
} catch (InterruptedException e) {}
}
}

1ー4。スレッドも待ち合わせ
複数のスレッドが起動している場合に、全てのスレッドの処理が終了してから、別の処理を
実行する場合は、jion() メソッドでスレッドの待ち合わせを行う。

---------------- ThreadSample4.java ----------------------
class ThreadSample4{
public static void main(String args[]){
ThreadB tb = new ThreadB();
ThreadC tc = new ThreadC();
tb.start();
tc.start();

int i;
try{
tb.join();
tc.join();

for(i = 0; i < 10; i++){
System.out.println("A : " + i);
Thread.sleep(1);
}
}
catch(InterruptedException e){}
}
}

//Threadを持ったクラス
class ThreadB extends Thread{
public void run(){
int i;
try{
for(i = 0; i < 10 ; i++){
System.out.println("B : " + i);
Thread.sleep(1);
}
}
catch(InterruptedException e){}
}
}
//Threadを持ったクラス
class ThreadC extends Thread{
public void run(){
int i;
try{
for(i = 0; i < 10 ; i++){
System.out.println("C : " + i);
Thread.sleep(1);
}
}
catch(InterruptedException e){}
}
}

1ー5。同期
同じの変数やオブジェクトを、複数のスレッドがアクセスすると、思わぬトラブルが発生する
ことがある。
そこで、この問題を解決する方法が、「同期」である。これは、共有するデータへの書き込み
を「同期」させて、あるスレッドが処理中は、他のスレッドは処理できない仕組みを作る。
これを、「排他処理」という。
この方法には次の2つの方法がある。
(1)synchronized 修飾子を用いて、メソッド単位で同期させる。
(2)syncronized ブロックを使用する。

マルチスレッドで、スレッドのロックを行うと、お互いがロックの解除を待ち続けて、動作が停
止することがある。これを「デッドロック」と呼ぶ。マルチスレッドでは、このデッドロックの
危険が生じる。

1)メソッドによる同期
================================================
synchronized 戻り値 メソッド名(引数リスト) {
処理;
}
===============================================
synchronized 宣言されたメソッドは、呼び出された時点で「ロック」され、他のスレッドか
ら呼び出しができなくなる。 この「ロック」は、メソッドの処理が終了すると解除される。
したがって、このメソッドは同時に複数動作することはない。
したのサンプルは、synchronized されたメソッドのテストである。
この synchronized修飾子をはずした場合も試してみよ。

------------ SynchronizedSample2.java -------------------------------
class SynchronizedSample2 extends Thread{
Share share;
SynchronizedSample2(Share share){
this.share = share;
}
public void run(){
while(true){
share.addCount(1);
share.addCount(-1);
}
}
public static void main(String args[]){
Share share = new Share();
new SynchronizedSample2(share).start();
new SynchronizedSample2(share).start();
}
}

class Share{
private int Count;

synchronized void addCount(int value){ //synchronized を取ってみる。
int currentCount = Count;
System.out.println(Thread.currentThread() + " : enter : " + Count);
Count += value;
if( Count != (currentCount + value)){
System.out.println(Thread.currentThread() + " : conflict : " + Count);
System.exit(-1);
}
System.out.println(Thread.currentThread() + " : exit : " + Count);
}
}

2)synchronizedブロックによる同期
同期を行いたい範囲を、 synchoronized ブロック内に記述する。
========================
synchoronized(obj) {
処理;
}
========================
下の例は、synchoronized ブロック内に、隔離した例である。
synchronized ブロックを解除した場合も試してみよ。

-------------- SynchoronizedSample3.java -------------------------
class SynchronizedSample3 extends Thread{
Share share;
SynchronizedSample3(Share share){
this.share = share;
}
public void run(){
while(true){
share.addCount(1);
share.addCount(-1);
}
}
public static void main(String args[]){
Share share = new Share();
new SynchronizedSample3(share).start();
new SynchronizedSample3(share).start();
}
}

class Share{
private int Count;

void addCount(int value){
synchronized(this){ //はずして、試してみよ
int currentCount = Count;
System.out.println(Thread.currentThread() + " : enter : " + Count);
Count += value;
if(Count != (currentCount + value)){
System.out.println(Thread.currentThread() + " : conflict : "
+ Count);
System.exit(-1);
}
System.out.println(Thread.currentThread() + " : exit : " + Count);
} //これも、はずしてみる。
}
}

1ー6。スレッド間の通信
スレッド間の通信に使われるメソッドには、次のものがある。
これらは、Objectクラスのメソッドである。
-------------------------------------------------------------------------
(1) void nitify() ロック解除を待っているスレッドの1つに通知を送る。
wait()を解除して、開始させる。
(2) void notifyAll() ロック解除を待っている全てのスレッドに通知を送る。
wait()を解除して、開始させる。
(3) void wait() ロックの解除を待つ。
(4) wait(log timeout) timeoutミリ秒の間ロック解除を待つ。
--------------------------------------------------------------------------
notify(),notifyAll()メソッドの呼び出しでも、すぐにはロックは解除されない。
synchoronized宣言されたメソッドやブロックの処理が終了してから、ロックは解除される。

------------------ TSyncSample1.java -------------------------------------
class TSyncSample1{
public static void main(String args[]){
Share share = new Share();
WriteThread thread1 = new WriteThread(share, "1");
ReadThread thread2 = new ReadThread(share, "2");
}
}

class WriteThread extends Thread{
Share share;
public WriteThread(Share share, String string){
super(string);
this.share = share;
start();
}
public void run(){
System.out.println("The Result is " + share.ReadProcess());
}
}

class ReadThread extends Thread{
Share share;
public ReadThread(Share share, String string){
super(string);
this.share = share;
start();
}
public void run(){
share.WriteProcess();
}
}

class Share{
int data = 0;

synchronized void WriteProcess(){
try{
System.out.println("Write : Processing...");
Thread.sleep(2000);
}
catch( Exception e ){
System.err.println("Exception : " + e);
}
data = 10;
notifyAll();
System.out.println("Write : Process done");
}

public synchronized int ReadProcess(){
System.out.println("Read : Waiting...");
try{
wait();
System.out.println("data = " + data);
}
catch( Exception e ){
System.err.println("Exception : " + e);
}
return data;
}
}