一、线程组(ThreadGroup)
一个系统中,如果线程数量很多,而且功能呢个分配比较明确,就可以将相同功能的线程放置在一个线程组里。打个比方,如果你有一本书,你就可以把它拿在手里,但是如果你有十本书,你就最好找一个书包,否则不方便携带。对于线程也是同等道理,如果你想处理十个或是上百个线程,最好还是将他们都装进对应的书包里。
线程组使用非常简单如下:
public class DiscoveryApplicaion {
public static volatile int i = 0;
static class Plustask implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getThreadGroup().getName()+"-"+Thread.currentThread().getName());
for (int k = 0; k < 1000; k++) {
i++;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread[] task = new Thread[10];
ThreadGroup group = new ThreadGroup("Group1");
for (int j = 0; j <task.length ; j++) {
task[j] = new Thread(group,new Plustask(),"T"+j);
task[j].start();
task[j].join();
}
System.out.println(group.activeCount());
group.list();
System.out.println(i);
}
}
线程组中有几个比较关键的方法,有助于你调试
- activeCount:可以获得活动线程的总数,但由于线程是动态的,因此这个值只是一个估计值,无法确定精确。
- list:可以打印这个线程组中的所有的线程信息,对调试有一定帮组。
- stop:它会停止线程组中所有的线程。看起开是一个很方便的功能。但是它会遇到和Thread.stop相同的问题,因此使用时需格外小心。
注:强烈建议大家在创建线程组的时候,给取一个好听的名字。如果你在调试時拿到的是一堆Thread-0、Thread-1我想大家一定会抓狂的。
二、守护线程(Daemon)
守护线程是一种特殊的线程,就和它的名字一样,他是系统的守护者,在后台默默的完成一些系统性的服务。比如垃圾回收线程、JIT线程就可以理解为守护线程。与之相对应的是用户线程,用户线程可以认为是系统的工作线程,它会完成这个程序应该要完成的业务操作。如果用户线程全部结束,这也意味着这个程序实际上无事可做了。守护线程要守护的对象已经不存在了,那么整个应用程序就自然应该结束。因此,当一个java应用内,只有守护线程時,java虚拟机就会自然退出。
public class DiscoveryApplicaion {
public static volatile int i = 0;
static class Plustask implements Runnable{
@Override
public void run() {
while (true){
System.out.println("i am alive");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
// SpringApplication.run(DiscoveryApplicaion.class, args);
Thread aa = new Thread(new Plustask());
aa.setDaemon(true);
aa.start();
Thread.sleep(2000);
}
}
这里要注意,设置守护线程必须在线程start()之前设置,否则你会得到以下异常,告诉你守护线程设置失败,但线程依然可以正常执行。只是被当作用户线程而已。
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.setDaemon(Thread.java:1352)
at Controller.DiscoveryApplicaion.main(DiscoveryApplicaion.java:28)
如果你不小心将setDaemon设置在了start()以后,那你就会诧异为什么程序永远不会停下来呢。
三、线程优先级(Priority)
优先级高的线程在竞争资源時会有更有优势,更可能抢占资源,当然这只是概率问题。如果运气不好,高优先级线程可能也会抢占失败。由于线程的优先级调度和底层操作系统有密切关系,在各个平台上表现不一,并且这种优先级产生的后果也可能不容易预测,无法精确控制。数字越大则优先级越高,但有效范围在1~10之间。
public class DiscoveryApplicaion {
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
static class HightPriority extends Thread{
static int count = 0;
public void run() {
while (true){
synchronized (DiscoveryApplicaion.class){
count++;
if (count > 100000){
System.out.println("HightPriority 优先处理完成");
break;
}
}
}
}
}
static class LowPriority extends Thread{
static int count = 0;
public void run() {
while (true){
synchronized (DiscoveryApplicaion.class){
count++;
if (count > 100000){
System.out.println("LowPriority 优先处理完成");
break;
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread hight = new HightPriority();
Thread low = new LowPriority();
low.setPriority(MAX_PRIORITY);
hight.setPriority(MIN_PRIORITY);
low.start();
hight.start();
}
}
可以尝试执行上述代码,可以看到,高优先级的线程在大部分情况下,都会首先完成任务。(但这不能确保所有情况下,一定都是这样)