1、线程优先级
java中的线程优先级的范围是1~10,默认的优先级是5。高优先级线程会优先于低优先级线程执行(数字越大优先级越高)。在一个线程内新建一个线程对象,则新建线程的优先级默认和父线程一样。示例:
public class PriorityThread extends Thread {
public PriorityThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ":priority-" + Thread.currentThread().getPriority()
+ ",loop-" + i);
}
}
public static void main(String args[]) {
System.out.println(Thread.currentThread().getName() + ":priority-" + Thread.currentThread().getPriority());
PriorityThread t1 = new PriorityThread("t1");
PriorityThread t2 = new PriorityThread("t2");
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
}
//结果
main:priority-5
t2:priority-10,loop-0
t2:priority-10,loop-1
t2:priority-10,loop-2
t2:priority-10,loop-3
t2:priority-10,loop-4
t1:priority-1,loop-0
t1:priority-1,loop-1
t1:priority-1,loop-2
t1:priority-1,loop-3
t1:priority-1,loop-4
线程t1先开始,但由于其优先级低于t2,因此t2先执行完
2、线程分类
java 中有两种线程:用户线程和守护线程。可以通过isDaemon()方法来区别它们,如果返回false,则说明该线程是用户线程,否则就是守护线程。用户线程一般用于执行用户级任务,而守护线程也就是后台线程,一般用来执行后台任务(比如垃圾回收)。需要注意的是:守护线程内创建的线程默认为守护线程,用户线程内创建的线程默认为用户线程。Java虚拟机在用户线程都结束后会退出,这可能会导致未执行完毕的守护线程得不到完全执行——也就是说守护线程随时可能停止工作。在JVM启动的时候通常会有一个非守护线程(用户线程),也就是通过main()启动的主线程,程序中所有的线程都是在main()或其调用的其他方法以及其调用的方法内再调用的方法创建的,那么按说创建的都是用户线程,那怎么创建守护线程呢?只需要设置线程的daemon属性为true即可:
public class DaemonThread {
static class InnerThread1 extends Thread {
public InnerThread1(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 10000; i++)
System.out.println(this.getName() + ":daemon-" + isDaemon());
}
}
static class InnerThread2 extends Thread {
public InnerThread2(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 5; i++)
System.out.println(this.getName() + ":daemon-" + isDaemon());
}
}
public static void main(String args[]) {
InnerThread1 t1 = new InnerThread1("t1");
InnerThread2 t2 = new InnerThread2("t2");
t1.setDaemon(true);
t1.start();
t2.start();
}
}
//结果
t1:daemon-true
t2:daemon-false
t2:daemon-false
t2:daemon-false
t2:daemon-false
t2:daemon-false
例子中在线程t2执行完之后看似程序已经执行结束了,由于线程t1是个守护线程,在所有非守护线程执行完毕之后JVM退出,该守护线程将无法继续执行(在非守护线程执行结束之前,该线程也在JVM中执行),因此不要在守护线程中做一些业务操作,示例:
public class DaemonThread {
static class InnerThread1 extends Thread {
public InnerThread1(String name) {
super(name);
}
public void run() {
System.out.println("复制文件开始");
String filePath = "D:\\1.png";
String fp = "D:\\2.png";
File f = new File(filePath);
byte[] b = new byte[1024];
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//Thread.sleep(1000);
fis = new FileInputStream(f);
fos = new FileOutputStream(fp);
int rc = 0;
while ((rc = fis.read(b, 0, 1024)) > 0) {
fos.write(b, 0, rc);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("复制文件结束");
}
}
static class InnerThread2 extends Thread {
public InnerThread2(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 5; i++)
System.out.println(this.getName() + ":daemon-" + isDaemon());
}
}
public static void main(String args[]) {
InnerThread1 t1 = new InnerThread1("t1");
InnerThread2 t2 = new InnerThread2("t2");
t1.setDaemon(true);
t1.start();
t2.start();
}
}
//结果
复制文件开始
t2:daemon-false
t2:daemon-false
t2:daemon-false
t2:daemon-false
t2:daemon-false
可以看到线程t1没有打印出"复制文件结束",也就是说线程t1还没有执行完JVM就退出了,导致复制的文件出错,不能查看:因此不要在守护线程中做一些业务操作
那守护线程有什么用呢?能用它来做些什么呢?
任何一个守护线程都是整个JVM中所有非守护线程的保姆,只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作,只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是GC (垃圾回收器),它就是一个很称职的守护者。User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行的必要了。不要认为所有的服务都可以分配给Daemon,比如读写操作或者计算逻辑,因为你不可能知道在所有的User完成之前,Daemon是否已经完成了预期的服务任务。一旦User退出了,可能大量数据还没有来得及读入或写出,计算任务也可能多次运行结果不一样。这对程序是毁灭性的。造成这个结果理由已经说过了:一旦所有User Thread离开了,虚拟机也就退出运行了。
Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.
When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:
The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.
All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.
Marks this thread as either a daemon thread or a user thread. The Java Virtual Machine exits when the only threads running are all daemon threads.