Javaのバックグラウンドスレッドの実例解析


本論文で研究したのは主にJavaのバックグラウンドスレッドに関する問題です。
今まで聞いたことがありませんが、javaにはバックグラウンドスレッドというものがあります。一般的に、JVM(JAVA仮想マシン)には、ユーザスレッドとバックグラウンドスレッドの2つのスレッドが含まれている。バックグラウンドスレッドとは、プログラムが実行されているときにバックグラウンドで提供される汎用的なサービスのスレッドであり、このスレッドはプログラムに不可欠なものではない。したがって、すべてのバックグラウンドスレッドが終了すると、ユーザスレッドが終了すると、プログラムは終了します。同時に、プロセス中のバックグラウンドスレッドをすべて殺します。逆に言えば、バックグラウンドスレッドがまだ実行されていない限り、プログラムは終了しません。メインを実行するのが非バックグラウンドスレッドです。
この特徴により、仮想マシンのユーザスレッドが全て終了し、サービスの対象がない場合、JVMは終了します。
この点のJDKソースの紹介はすでにこの点を説明しました。
*Marks this thread as either a{@linkpline芫is Daemen daemen}thread
*or a user thread.The Java Virtual Machine exits when the only
*threads running are all daemen 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.isDaemen()=true
Daemen Spawn 0 started
Daemen Spawn 1 started
Daemen Spawn 2 started
Daemen Spawn 3 started
Daemen Spawn 4 started
Daemen Spawn 5 started
Daemen Spawn 6 started
Daemen Spawn 7 started
Daemen Spawn 8 started
Daemen Spawn 9 started
t[0].isDaementrue
t[1].isDaementrue
t[2].isDaementrue
t[3].isDaementrue
t[4].isDaementrue
t[5].isDaementrue
t[6].isDaementrue
t[7].isDaementrue
t[8].isDaementrue
t[9].isDaementrue
3.ThreadFactoryのオブジェクトをExecutors.newCachedThreadPool()方法で指定します。この方法によって、私たちも
私たちは起動スレッドをバックグラウンドスレッドに設定したいです。

/*      ,           :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]Concerency.DaemonFromFactory@56214c1
Thread[Thread-2,5,main]Concerency.DaemonFromFactory@5724147d
Thread[Thread-0,5,main]Concerency.DaemonFromFactory@144fe080
Thread[Thread-1,5,main]Concerency.DaemonFromFactory@104fa29e
Thread[Thread-8,5,main]Concerency.DaemonFromFactory@5b069a7f
Thread[Thread-9,5,main]Concerency.DaemonFromFactory@1a7288d1
Thread[Thread-7,5,main]Concerency.DaemonFromFactory@25144c3e
Thread[Thread-4,5,main]Concerency.DaemonFromFactory@288523d
Thread[Thread-6,5,main]Concerency.DaemonFromFactory@1edae2a8
Thread[Thread-5,5,main]Concerency.DaemonFromFactory@626007aa
Thread[Thread-3,5,main]Concerency.DaemonFromFactory@56214c1
Thread[Thread-2,5,main]Concerency.DaemonFromFactory@5724147d
Thread[Thread-6,5,main]Concerency.DaemonFromFactory@1edae2a8
Thread[Thread-5,5,main]Concerency.DaemonFromFactory@626007aa
Thread[Thread-4,5,main]Concerency.DaemonFromFactory@288523d
Thread[Thread-9,5,main]Concerency.DaemonFromFactory@1a7288d1
Thread[Thread-7,5,main]Concerency.DaemonFromFactory@25144c3e
Thread[Thread-8,5,main]Concerency.DaemonFromFactory@5b069a7f
Thread[Thread-1,5,main]Concerency.DaemonFromFactory@104fa29e
Thread[Thread-0,5,main]Concerency.DaemonFromFactory@144fe080
Thread[Thread-2,5,main]Concerency.DaemonFromFactory@5724147d
Thread[Thread-3,5,main]Concerency.DaemonFromFactory@56214c1
Thread[Thread-6,5,main]Concerency.DaemonFromFactory@1edae2a8
Thread[Thread-1,5,main]Concerency.DaemonFromFactory@104fa29e
Thread[Thread-0,5,main]Concerency.DaemonFromFactory@144fe080
Thread[Thread-7,5,main]Concerency.DaemonFromFactory@25144c3e
Thread[Thread-8,5,main]Concerency.DaemonFromFactory@5b069a7f
Thread[Thread-5,5,main]Concerency.DaemonFromFactory@626007aa
Thread[Thread-9,5,main]Concerency.DaemonFromFactory@1a7288d1
Thread[Thread-4,5,main]Concerency.DaemonFromFactory@288523d
Thread[Thread-2,5,main]Concerency.DaemonFromFactory@5724147d
Thread[Thread-3,5,main]Concerency.DaemonFromFactory@56214c1
Thread[Thread-8,5,main]Concerency.DaemonFromFactory@5b069a7f
Thread[Thread-7,5,main]Concerency.DaemonFromFactory@25144c3e
Thread[Thread-4,5,main]Concerency.DaemonFromFactory@288523d
Thread[Thread-6,5,main]Concerency.DaemonFromFactory@1edae2a8
Thread[Thread-1,5,main]Concerency.DaemonFromFactory@104fa29e
Thread[Thread-0,5,main]Concerency.DaemonFromFactory@144fe080
Thread[Thread-9,5,main]Concerency.DaemonFromFactory@1a7288d1
Thread[Thread-5,5,main]Concerency.DaemonFromFactory@626007aa
Thread[Thread-3,5,main]Concerency.DaemonFromFactory@56214c1
Thread[Thread-2,5,main]Concerency.DaemonFromFactory@5724147d
Thread[Thread-8,5,main]Concerency.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 ADaemen
しかし、状況が次のようになったら、出力の結果はまた違ってきます。

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 ADaemen
This shoud always run?
締め括りをつける
以上がJavaにおけるバックグラウンドスレッドのインスタンス解析のすべての内容です。興味のある方は引き続き当駅の他のテーマを参照してください。友達のサポートに感謝します。