欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java中后台线程实例解析

程序员文章站 2023-08-13 19:29:06
本文研究的主要是java中后台线程的相关问题,具体介绍如下。 以前从来没有听说过,java中有后台线程这种东西。一般来说,jvm(java虚拟机)中一般会包括俩种线程,分...

本文研究的主要是java中后台线程的相关问题,具体介绍如下。

以前从来没有听说过,java中有后台线程这种东西。一般来说,jvm(java虚拟机)中一般会包括俩种线程,分别是用户线程和后台线程。所谓后台线程(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中后台线程实例解析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!