Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

マルチスレッド実行時の挙動がMacとWinで違う?

初めまして、マルコムXです。
マルチスレッドの実行の勉強として下記の様なサンプルコードを作りました。
RuntimeTestクラスのスレッドと
ParallelClassクラスのスレッドが並行で動くというものです。
ParallelClassのwhile文でiが150000を超えると
RuntimeTestのwhile文は処理を抜け、ParallelClassを止めるという動作を想定しています。
しかし、
下記のRuntimeTestクラスのmainメソッド内でwhile文から抜けるハズの条件が認識されない状態となってしまい、いつまで経っても処理を抜けることができません。

そこでRuntimeTestのwhile文内でthread.sleep(10);を入れてwhileが回る速度を落とすと意図した通りに処理を抜けるようになりました。

windowsで同様のプログラムを実行した場合sleepを入れなくても上手く動きました。

sleepを入れないとwhileの条件が上手く認識できないのは何故なのでしょうか?
また、windowsでは上手く動くというのは何故なのでしょうか?
さっぱり解らず困っています。

どなたか何卒宜しくお願いいたします。
____________________________________
使用しているMacの環境は以下です。
(winは知り合いに頼んで実行してもらったので解りません)

・MacOS10.6.8
・java version 1.6.0_26
・統合開発環境 Eclipse3.7
____________________________________

__RuntimeTest.java___________________________
public class RuntimeTest {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // 並行処理を行うクラスのインスタンスを生成
        ParallelClass pc = new ParallelClass();
        // スレッドを作成
        Thread t = new Thread(pc);
        // ParallelClassのrunメソッド実行
        t.start();
        String name = null;
        while ((name = pc.getFilename()) == null) {
            //Q : sleep()でwhileが回る速度を調整
            //Q : sleep処理をなくすとwhile文を抜けないのは何故?
            /*
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }
            */
        }
        //ParallelClassのwhile文でiの値が150000になったらflagを立てる
        pc.setFlag(true);
        System.out.println("ファイル名:"+pc.getFilename());
    }
}

__ParallelClass.java_________________________

import java.util.*;

public class ParallelClass implements Runnable {
    private String filename;
    private boolean flag = false;

    public void run() {
        
        // Scanner scan = new Scanner(System.in);
        int i = 0;
        while (true) {
            System.out.println("parallel回転中!"+i);
            if (i == 150000) {
                this.filename = "test.csv";
            }
            i++;
            if(this.flag == true){
                break;
            }
        }
        System.out.println("終わり");
    }
    
    public String getFilename() {
        return filename;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

4

回答

4787

閲覧

4件の回答

評価

0

ループは基本的にsleepしないと処理を占有する。
メインスレッドが占有すると子のスレッドの処理が行われず、filenameにいつまでも値が入らない。

挙動の違いは、ネイティブのスレッドの仕組みの違いだろう。
たぶん、以前のWindowsなら同様に止まってしまう気がする。


というのは全部コードから得られる予想だけど、いずれにしても長時間が想定されるループには本来sleep必須。

評価

0

なるほど、ループには本来sleep必須なんですね。
勉強になりました。
有難うございます。

因みに、sleepさせない場合の挙動なのですが、
子のスレッドの処理が優先して行われているようです。
ParallelClassのwhileがずっとループしていて、filenameの値は入っているみたいです。

早く動き過ぎるとメインスレッド側でpc.getFilename()とかしてても値が取れないんですかねー?

評価

0

メモリバリアの問題と思います。
ParallelClassのフィールドflagにvolatile指定をするか、flagの読み書きにsynchronizedメソッドを使う等の対処が必要では?

うまく動く/動かないは、OSの違いもあり得ますが、CPU(コア)数やHotSpotVMの最適化の違い(ClientVMかServerVMか)があるのではと推測します。

評価

0

Laさん、
情報ありがとうございました。
synchronizedメソッドもvolatileも使ってみたのですが、どうも上手くいかずでした。
とりあえず、Threadを同時進行したい場合はsleepを使用したいと思います。

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。