Javaスレッド学習


スレッドから情報を取得
メインプログラムの無限ループをポーリングし、サブスレッドが実行されるまでサブスレッドから戻り値を取得します(戻り値は0ではありません)
public class ReturnThread extends Thread {
  private int time;
  private int result;

  public ReturnThread(int time) {
    this.time = time;
  }

  public void run() {
    try {
      TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
    result = time;
  }

  public int getResult() {
    return result;
  }
}

public class ReturnThreadShell {

  public static void main(String[] args) {
    Random r = new Random(47);
    ReturnThread[] threads = new ReturnThread[5];
    for (int i = 0; i < 5; i++) {
      int time = r.nextInt(10);
      ReturnThread thread = new ReturnThread(time);
      threads[i] = thread;
      thread.start();
    }
    for (int i = 0; i < threads.length; i++) {
      while (true) {
        int rslt = threads[i].getResult();
        if (rslt != 0) {
          System.out.println("thread " + i + "
              is finish. return value is " + rslt);
          break;
        }
      }
    }
  }
}
//thread 0 is finish. return value is 8
//thread 1 is finish. return value is 5
//thread 2 is finish. return value is 3
//thread 3 is finish. return value is 1
//thread 4 is finish. return value is 1

コールバックサブスレッドの実行が完了したら、メインスレッドを呼び出す方法
public class CallbackThread extends Thread {
  private int time;
  private CallbackThreadShell callback;

  public CallbackThread(int time, CallbackThreadShell callback) {
    this.time = time;
    this.callback = callback;
  }

  public void run() {
    try {
      TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
    callback.receiveResult(time, callback.threadId);
  }
}

public class CallbackThreadShell {
  private int time;
  protected int threadId;

  public CallbackThreadShell(int time, int threadId) {
    this.time = time;
    this.threadId = threadId;
  }

  public void runThread() {
    CallbackThread thread = new CallbackThread(time, this);
    thread.start();
  }

  public void receiveResult(int result, int threadId) {
    System.out.println("thread " + threadId 
        + " is finish. return value is " + result);
  }

  public static void main(String[] args) {
    Random r = new Random(47);
    for (int i = 0; i < 5; i++) {
      CallbackThreadShell shell = new CallbackThreadShell(r.nextInt(10), i);
      shell.runThread();
    }
  }
}
//thread 3 is finish. return value is 1
//thread 4 is finish. return value is 1
//thread 2 is finish. return value is 3
//thread 1 is finish. return value is 5
//thread 0 is finish. return value is 8

同期
同期ブロックjavaは、他のすべてのスレッドが共有リソースを使用する方法を阻止することはできません.彼は、同じオブジェクトに同期した他のスレッドが共有リソースを使用することを防止するしかありません.
同期メソッド
同期の代替方法
1クラス変数の代わりにローカル変数を使用
2単純なタイプのメソッドパラメータは安全です.javaが値を介して伝達するのは参照伝達パラメータではなく、オブジェクトタイプのメソッドパラメータであり、finalであればスレッドが安全です.
3スレッドセキュリティ以外のクラスを、スレッドセキュリティのクラスのプライベートフィールドとして使用します.
デッドロック
デッドロック防止不要なスレッド同期を回避!!
スレッドスケジューリング
プリエンプトとコラボレーションプリエンプトスレッドスケジューラは、スレッドがCPUを公平に楽しむ時間を決定し、このスレッドを一時停止し、CPU制御権を別のスレッドに渡す.(飢餓問題は発見しにくい)
コラボレーションスレッドスケジューラは、CPU制御権が他のスレッドに渡される前に、実行中のスレッドが自分で一時停止するのを待つ.
他のスレッドに有利にするために、1つのスレッドは、一時停止の準備を一時停止または指示する方法があります.
I/Oブロック時にブロック、同期する他のオブジェクトはブロックです.スレッドが停止しなければならず、彼が持っていないリソースを待つと、ブロックが発生します.スレッドは、すでにスレッドが所有しているロックを解放しません.
やめてyield().スレッドは、他の優先度の同じスレッドが実行されるように一時停止します.
休眠するsleep().スレッドは、他のスレッドが実行の準備ができているかどうかにかかわらず一時停止します.
スリープスレッドを呼び出すinterrupt()メソッドは、スレッドを呼び覚ますことができます.これは、スレッドとThreadオブジェクトの重要な違いの1つです(スレッドがスリープ中でも、メソッドを呼び出して対話することができます)呼び覚ますと、スリープスレッドにInterruptedExceptionが得られます.
InterruptedExceptionでスレッドを終了する例

public void run(){
  while(true){
    try{ Thread.sleep(300000);
    }catch(InterruptedException e){ break;}}}

接続スレッドjoin().1つのスレッドは、接続するスレッド(join()メソッドが呼び出されるスレッド)の終了を待つ別のスレッドの結果を必要とする.
オブジェクトを待つwait().オブジェクトまたはリソースがステータスに達するまで実行を一時停止し、接続はスレッドが終了することを知るために実行を一時停止します.待機中は、他のスレッドからnotify()または時間切れの通知を受け、スレッドがinterrupt()を中断するまで、オブジェクトのロックを解放して一時停止します(ただし、他のオブジェクトのロックではありません).
待機スレッドが通知されると、待機オブジェクトのロックを再取得しようとし、成功するとwait()呼び出し直後の文を実行し続け、失敗するとロックが得られるまでオブジェクトをブロックします.
while (pool.isEmpty()) {
  try {
    pool.wait();
    //      ,    ,       
    //   pool.isEmpty(),            ,pool       
  } catch (InterruptedException ex) {}
}
//       ,     。。。
connection = (Socket) pool.remove(0);

synchronized (pool) {
  pool.add(pool.size(), request);
  pool.notifyAll();
}

優先度ベースのプリエンプトsetPriority()メソッド
終了run()メソッドが戻るとスレッドは破棄され,他のスレッドはCPUを引き継ぐことができる.
スレッドプール
実装方法
1プールが最初に作成されると、一定数のスレッドが割り当てられ、プールが空の場合、すべてのスレッドが待機し、プールにタスクを追加すると、待機しているすべてのスレッドが通知されます.スレッドが割り当てられたタスクを終了すると、プールに戻って新しいタスクを待機します.
2スレッド自体をプールに配置し,メインプログラムがプールからスレッドを取り出し,タスクを割り当てる.各スレッドが終了したらプールに戻ります.
一例として、マルチスレッド圧縮ファイル
public class GZipThread extends Thread {

  private List pool;
  private static int filesCompressed = 0;

  public GZipThread(List pool) {
    this.pool = pool;
  }

  private static synchronized void incrementFilesCompressed() {
    filesCompressed++;
    System.out.println(filesCompressed);
  }

  public void run() {
    while (filesCompressed != GZipAllFiles.getNumberOfFilesToBeCompressed()) {
      File input = null;
      synchronized (pool) {
        while (pool.isEmpty()) {
          if (filesCompressed == GZipAllFiles.getNumberOfFilesToBeCompressed()) {
            System.out.println("Thread ending");
            return;
          }
          try {
            pool.wait();
          } catch (InterruptedException ex) {
          }
        }
        input = (File) pool.remove(pool.size() - 1);
        incrementFilesCompressed();
      }
      // don't compress an already compressed file
      if (!input.getName().endsWith(".gz")) {
        try {
          InputStream in = new FileInputStream(input);
          in = new BufferedInputStream(in);
          File output = new File(input.getParent(), input.getName() + ".gz");
          if (!output.exists()) { // Don't overwrite an existing file
            OutputStream out = new FileOutputStream(output);
            out = new GZIPOutputStream(out);
            out = new BufferedOutputStream(out);
            int b;
            while ((b = in.read()) != -1)
              out.write(b);
            out.flush();
            out.close();
            in.close();
          }
        } catch (IOException ex) {
          System.err.println(ex);
        }
      } // end if
    } // end while
  } // end run
} // end ZipThread

public class GZipAllFiles {

  public final static int THREAD_COUNT = 4;
  private static int filesToBeCompressed = -1;

  public static void main(String[] args) {
    Vector pool = new Vector();
    GZipThread[] threads = new GZipThread[THREAD_COUNT];
    for (int i = 0; i < threads.length; i++) {
      threads[i] = new GZipThread(pool);
      threads[i].start();
    }
    int totalFiles = 0;
    for (int i = 0; i < args.length; i++) {
      File f = new File(args[i]);
      if (f.exists()) {
        if (f.isDirectory()) {
          File[] files = f.listFiles();
          for (int j = 0; j < files.length; j++) {
            //       
            if (!files[j].isDirectory()) {
              totalFiles++;
              synchronized (pool) {
                pool.add(0, files[j]);
                pool.notifyAll();
              }
            }
          }
        } else {
          totalFiles++;
          synchronized (pool) {
            pool.add(0, f);
            pool.notifyAll();
          }
        }
      } // end if
    } // end for
    filesToBeCompressed = totalFiles;
    System.out.println("totalFiles " + filesToBeCompressed);
    //        ,             
    //           ,        ,          
    for (int i = 0; i < threads.length; i++) {
      threads[i].interrupt();
    }
  }

  public static int getNumberOfFilesToBeCompressed() {
    return filesToBeCompressed;
  }