有关线程的相关知识(下)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://glhcode.blog.csdn.net/article/details/70339618

转载请标明出处:
http://blog.csdn.net/hai_qing_xu_kong/article/details/70339618
本文出自:【顾林海的博客】

前言

在上一篇文章《有关线程的相关知识(1)》 一文中已经讲了线程的两种创建方式以及6个状态,这篇文章就把接下来的东西加上,各位看官,提好裤子,上车咯。



线程的中断

在java中,当所有非守护进程运行结束或是其中一个线程调用了System.exit()方法时java程序就运行结束,这里面的守护线程是一种特殊的线程,它是系统的守护者,在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程(动态编译器)就可以理解为守护线程,如果守护线程要守护的对象已经不存在了,那么整个应用程序就会结束,也就是说,在Java应用中如果只剩下守护线程时,Java虚拟机就会自然退出。

我们来编写这样一个程序,创建一个线程,在这个线程中一直打印信息,接着我们给这个线程设置为守护线程,并在主线程中休眠2秒后,看看创建的线程是否继续打印:

public class Daemon implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){

            System.out.println("hello....");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }

}
public class Client {
    public static void main(String[] args) {
        Thread daemonThread=new Thread(new Daemon());
        daemonThread.setDaemon(true);
        daemonThread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

输出的结果:

hello….
hello….
hello….

可以发现将daemonThread设置为守护线程,系统中只有主线程main为用户线程,在main线程休眠2秒后退出,整个程序也结束,如果不把daemonThread设置为守护线程,main线程结束后,daemonThread线程会不停的打印,永远不会结束。

在Java中提供了中断机制,可以使用它来结束一个线程,这种机制要求线程检查它是否被中断,然后决定是不是响应这个中断请求,并且线程是可以忽略这个中断请求。

接下来创建一个线程并不停打印累加的number值,在打印前先判断当前线程是否被中断,如果被中断,就打印信息,接着退出。

public class MyThread extends Thread{

    private int number=0;

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            if(isInterrupted()){
                System.out.println("interrupted...");
                return;
            }

            System.out.println("number="+number);

            number++;
        }
    }

}
public class Client {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThread.interrupt();

    }
}

输出:

…………………..
number=465110
number=465111
number=465112
interrupted…

可以看出当myThread线程被中断后,程序就运行终止,Thread类有一个表明线程是否被中断的属性,类型是布尔值,当线程的interrupt()方法被调用时,这个属性就会被赋值为true。

isInterrupted()会返回上面提到的属性值,除了使用isInterrupted()方法检查线程是否被中断,还有一个方法interrupted()也是检查线程的中断与否,两种方法的区别在与:isInterrupted()不能改变interrupted属性的值,但interrupted()方法能设置interrupted 属性为false。




线程的休眠与恢复

线程提供一个sleep()方法,表示休眠,在休眠的这段时间,线程不占用计算机的任何资源,sleep()方法接受整型数值作为参数,来表明线程挂起执行的毫秒数。sleep()方法的另一种使用方式是通过 TimeUnit枚举类元素进行调用,它接受的参数单位是秒,最后会被转化成毫秒。

在接下来的程序中,通过TimeUnit类的SECONDS属性的sleep()方法来挂起一秒钟,之后输出信息。

public class MyThread extends Thread{

    private int number=0;

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){            
            System.out.println("number="+number);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("InterruptedException...");
            }
            number++;
        }
    }

}
public class Client {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThread.interrupt();

    }
}

在主类中,我们运行这个线程并在挂起一段时间后中断这个线程,我们在myThread线程中的调用sleep()方法时捕获InterruptedException异常时输出一段信息(推荐当线程被中断时,可以在捕获这个异常时进行释放或者关闭线程正在使用的资源)。

输出:

number=2
number=3
number=4
InterruptedException…
number=5
number=6
number=7
number=8
…………….
…………….


除了sleep()方法外,Java并发API还提供了另一个方法来使线程对象释放CPU,这个方法是yield()方法,它会通知JVM这个线程对象可以释放CPU了,但JVM并不保证遵循这个要求。




等待线程的终止

有时候,我们需要等待线程的终止,比如初始化资源,只有在初始化完毕后才能继续执行下去,达到这个目的,我们可以使用Thread类的join()方法,当一个线程对象调用join()方法时,调用它当线程将被挂起,直到这个线程对象完成它当任务。

我们创建两个个线程,其中每隔一秒计数,当第一个线程到达5并且第二线程到达6时,主线程才能继续执行下去。

public class MyThread1 extends Thread{

    private int number=0;

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(number<=5){           
            System.out.println("number="+number);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("InterruptedException...");
            }
            number++;
        }
    }

}
public class MyThread2 extends Thread{

    private int number=0;

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(number<=6){           
            System.out.println("number="+number);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("InterruptedException...");
            }
            number++;
        }
    }

}
public class Client {
    public static void main(String[] args) {
        MyThread1 myThread1=new MyThread1();
        MyThread2 myThread2=new MyThread2();
        myThread1.start();
        myThread2.start();

        try {
            myThread1.join();
            myThread2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("终于轮到我了.....");

    }
}

输出:

number=0
number=0
number=1
number=1
number=2
number=2
number=3
number=3
number=4
number=4
number=5
number=5
number=6
终于轮到我了…..

当myThread1与myThread2都结束时,主线程对象才会继续执行下去。




线程的分组

Java并发API提供了一个功能,能够把线程分组,这样的话,一组线程可以当作一个单一的单元 , Java提供了ThreadGroup类表示一组线程,线程组可以包含线程对象,也可以包含其他的线程组对象,它是一个树形结构。

public class ThreadGroupClient implements Runnable{

    @Override
    public void run() {
        while(true){
            System.out.println("group:"+Thread.currentThread().getThreadGroup().getName()+"----thread:"+Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ThreadGroup threadGroup=new ThreadGroup("group");
        Thread thread1=new Thread(new ThreadGroupClient(),"thread1");
        Thread thread2=new Thread(new ThreadGroupClient(),"thread2");
        thread1.start();
        thread2.start();
        System.out.println(threadGroup.activeCount());
        threadGroup.list();
    }

}

输出:

0
group:main—-thread:thread2
group:main—-thread:thread1
java.lang.ThreadGroup[name=group,maxpri=10]
group:main—-thread:thread1
group:main—-thread:thread2
group:main—-thread:thread1
group:main—-thread:thread2

创建一个名叫group的线程组,并将thread1和thread2加入这个线程组中,activeCount()可以获得活动线程的总数,但由于线程是动态的,因此这个值只是一个估计值,无法确定精确,list()方法打印这个线程组中所有的线程信息。

展开阅读全文

没有更多推荐了,返回首页