Javaにおけるバックグラウンドスレッドのインスタンス解析

10199 ワード

本稿では主にJavaにおけるバックグラウンドスレッドに関する問題を検討し,具体的には以下のように紹介する.
以前は聞いたことがありませんが、javaにはバックグラウンドスレッドというものがあります.一般的に、JVM(JAVA仮想マシン)には、ユーザスレッドとバックグラウンドスレッドの2つのスレッドが含まれます.バックグラウンドスレッド(daemon)とはスレッドとは、プログラムの実行時にバックグラウンドで提供される汎用的なサービスのスレッドであり、このスレッドはプログラムに不可欠な部分ではない.したがって、バックグラウンド以外のすべてのスレッドが終了すると、すなわちユーザスレッドが終了すると、プログラムは終了する.同時に、プロセス内のすべてのバックグラウンドスレッドが殺される.逆に言えば、バックグラウンド以外のスレッドがまだ実行されている場合、プログラムは終了しません.main()を実行するのはバックグラウンド以外のスレッドです.
この特徴に基づいて,仮想マシン内のユーザスレッドがすべて実行を終了すると,デーモンスレッドにサービスのないオブジェクトが終了すると,JVMも終了する.
この点はJDKソースコードの紹介で説明されています.
* Marks this thread as either a {@linkplain #isDaemon daemon} thread * or a user thread. The Java Virtual Machine exits when the only * threads running are all daemon threads.
1.バックグラウンドスレッドの起動条件:

/*           SetDaemon()  ,              。
*        ,           ,  Main         
*                     。            
* JVM        ,              */
public class DaemonRunner implements Runnable {
	@Override
	 public void run() {
		while (true) {
			for (int i = 0; i < 3; i++) {
				System.out.println("    " + i);
			}
		}
	}
	public static void main(String[] args) {
		Thread daemon = new Thread(new DaemonRunner());
		daemon.setDaemon(true);
		daemon.start();
		Scanner s = new Scanner(System.in);
		String string=s.nextLine();
		Runtime.getRuntime().addShutdownHook(new Thread(){
			@Override
			   public void run() {
				super.run();
				System.out.println("JVM  ");
				try {
					TimeUnit.MILLISECONDS.sleep(50);
				}
				catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		);
	}
}

2.バックグラウンドスレッドで開始されたスレッドはすべてバックグラウンドスレッドに属します.バックグラウンドスレッドであることは明確に指定されていませんが、バックグラウンドスレッドです.

/*      isDaemon()                。         ,
*                       
*       ,Daemon           ,          ,           
*     ,           。  ,Daemon         ,         yield  
*                */
class Daemon implements Runnable{
	private Thread[] t = new Thread[10];
	@Override
	 public void run() {
		for (int i = 0; i < t.length; i++) {
			t[i] = new Thread(new DaemonSpawn());
			t[i].start();
			System.out.println("DaemonSpawn " + i + "started");
		}
		for (int i = 0; i < t.length; i++) {
			System.out.println("t[" + i + "].isDaemon" + t[i].isDaemon());
		}
		while (true) {
			Thread.yield();
		}
	}
}
class DaemonSpawn implements Runnable{
	@Override
	 public void run() {
		while (true) {
			Thread.yield();
		}
	}
}
public class Daemons {
	public static void main(String[] args) {
		Thread d = new Thread(new Daemon());
		d.setDaemon(true);
		d.start();
		System.out.println("d.isDaemon()=" + d.isDaemon());
		try {
			TimeUnit.SECONDS.sleep(1);
			//                     。
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

最後の実行結果は次のとおりです.
d.isDaemon()=true DaemonSpawn 0started DaemonSpawn 1started DaemonSpawn 2started DaemonSpawn 3started DaemonSpawn 4started DaemonSpawn 5started DaemonSpawn 6started DaemonSpawn 7started DaemonSpawn 8started DaemonSpawn 9started t[0].isDaemontrue t[1].isDaemontrue t[2].isDaemontrue t[3].isDaemontrue t[4].isDaemontrue t[5].isDaemontrue t[6].isDaemontrue t[7].isDaemontrue t[8].isDaemontrue t[9].isDaemontrue
3.Executors.newCachedThreadPool()メソッドにThreadFactoryのオブジェクトを指定します.このメソッドでは、起動したいスレッドをバックグラウンドスレッドに設定することもできます.

/*      ,           :Executors.newCachedThreadPool(new DaemonThreadFactory()
*          ThreadFactory   ,             ,                 
*       。*/
class DaemonThreadFactory implements ThreadFactory{
	@Override
	  public Thread newThread(Runnable r) {
		Thread t = new Thread(r);
		t.setDaemon(true);
		return t;
	}
}
/*      , Main   ,     Main         ,“ System.out.println("All dameons started");”
*             。          ,       ,         ,   Main  
*         ,    Main             ,  Main        。  ,
*               。JVM      。*/
public class DaemonFromFactory implements Runnable {
	@Override
	  public void run() {
		try {
			while (true) {
				TimeUnit.MILLISECONDS.sleep(100);
				System.out.println(Thread.currentThread() + " " + this);
			}
		}
		catch (InterruptedException e) {
			System.out.println("Interrupted");
		}
	}
	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool(new DaemonThreadFactory());
		for (int i = 0; i < 10; i++) {
			exec.execute(new DaemonFromFactory());
		}
		System.out.println("All dameons started");
		try {
			TimeUnit.MILLISECONDS.sleep(500);
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

最後の出力の結果は次のとおりです.
All dameons started Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1 Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d Thread[Thread-0,5,main] Concurrency.DaemonFromFactory@144fe080 Thread[Thread-1,5,main] Concurrency.DaemonFromFactory@104fa29e Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f Thread[Thread-9,5,main] Concurrency.DaemonFromFactory@1a7288d1 Thread[Thread-7,5,main] Concurrency.DaemonFromFactory@25144c3e Thread[Thread-4,5,main] Concurrency.DaemonFromFactory@288523d Thread[Thread-6,5,main] Concurrency.DaemonFromFactory@1edae2a8 Thread[Thread-5,5,main] Concurrency.DaemonFromFactory@626007aa Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1 Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d Thread[Thread-6,5,main] Concurrency.DaemonFromFactory@1edae2a8 Thread[Thread-5,5,main] Concurrency.DaemonFromFactory@626007aa Thread[Thread-4,5,main] Concurrency.DaemonFromFactory@288523d Thread[Thread-9,5,main] Concurrency.DaemonFromFactory@1a7288d1 Thread[Thread-7,5,main] Concurrency.DaemonFromFactory@25144c3e Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f Thread[Thread-1,5,main] Concurrency.DaemonFromFactory@104fa29e Thread[Thread-0,5,main] Concurrency.DaemonFromFactory@144fe080 Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1 Thread[Thread-6,5,main] Concurrency.DaemonFromFactory@1edae2a8 Thread[Thread-1,5,main] Concurrency.DaemonFromFactory@104fa29e Thread[Thread-0,5,main] Concurrency.DaemonFromFactory@144fe080 Thread[Thread-7,5,main] Concurrency.DaemonFromFactory@25144c3e Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f Thread[Thread-5,5,main] Concurrency.DaemonFromFactory@626007aa Thread[Thread-9,5,main] Concurrency.DaemonFromFactory@1a7288d1 Thread[Thread-4,5,main] Concurrency.DaemonFromFactory@288523d Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1 Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f Thread[Thread-7,5,main] Concurrency.DaemonFromFactory@25144c3e Thread[Thread-4,5,main] Concurrency.DaemonFromFactory@288523d Thread[Thread-6,5,main] Concurrency.DaemonFromFactory@1edae2a8 Thread[Thread-1,5,main] Concurrency.DaemonFromFactory@104fa29e Thread[Thread-0,5,main] Concurrency.DaemonFromFactory@144fe080 Thread[Thread-9,5,main] Concurrency.DaemonFromFactory@1a7288d1 Thread[Thread-5,5,main] Concurrency.DaemonFromFactory@626007aa Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1 Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f
4.まず、ユーザスレッドが突然終了した場合、バックグラウンドスレッドはfinally句を実行せずにrunメソッドを終了することを認識すべきである.

/*           ,    finally      ,         setDaemon()   ,    
* finally       .
*         。        finally     ,          。        
*                 ,           。    main()   ,JVM           
*   。                  ,              。    Executor     
*      ,  Executor               。*/
class ADaemon implements Runnable{
  @Override
  public void run() {
    System.out.println("Starting ADaemon");
    try {
      TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
      System.out.println("Exiting via InterruptedException");
    }finally {
      System.out.println("This should always run?");
    }
  }
}
public class DaemonsDontRunFinally {
  public static void main(String[] args) {
    Thread t = new Thread(new ADaemon());
    t.setDaemon(true);
    t.start();
  }
}

最後の出力の結果は次のとおりです.
Starting ADaemon
しかし、状況が次のようになると、出力の結果はまた異なります.

class ADaemon implements Runnable{
  @Override
  public void run() {
    System.out.println("Starting ADaemon");
    try {
      TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
      System.out.println("Exiting via InterruptedException");
    }finally {
      System.out.println("This should always run?");
    }
  }
}
public class DaemonsDontRunFinally {
  public static void main(String[] args) {
    Thread t = new Thread(new ADaemon());
    t.setDaemon(true);
    t.start();
    try {
      TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

プライマリ・スレッドは突然終了しないため、プライマリ・スレッドはスリープ中にバックグラウンド・スレッドが実行される時間が得られるため、最後の印刷の結果は:
Starting ADaemon This should always run?
まとめ
以上、Javaにおけるバックグラウンドスレッドの実例解析のすべての内容について、皆さんの役に立つことを願っています.興味のある方は、当駅の他の関連テーマを引き続き参照してください.不足点があれば、コメントを歓迎します.当駅のサポートに感謝します.