Java多线程(三、线程的一些概念)

isAlive()和join()的使用

我们之前说到,最好让主线程最后结束,在前面的例子中,都是通过调用sleep()方法,让线程睡眠产生时差来实现的,经过足够长时间的延迟以确保所有子线程都先于主线程结束。然而,这不是一个令人满意的解决方法。它也带来了一个大问题:一个线程如何直到另一个线程已经结束?幸运的是,Thread类提供了回答此问题的方法。

有两个方法可以判断一个线程是否已经结束。第一,可以在线程中调用isAlive()。这种方法由Thread类定义,它的通常形式为:

public final native boolean isAlive();
如果所调用线程仍在运行,isAlive()返回true,否则返回false。但isAlive()很少用到,等待线程结束更常用到的方法是调用join(),方法为:
public final void join() throws InterruptedException

该方法能够等待所调用线程结束。join()的重载方法允许给等待指定线程结束定义一个最大时间。

下面看一个例子:

public class Test3 {

	public static void main(String[] args) throws InterruptedException {
		//同时运行了三个子线程
		MyThread1 t1=new MyThread1("child Thread One");
		MyThread1 t2=new MyThread1("child Thread Two");
		MyThread1 t3=new MyThread1("child Thread Three");
		//等待所调用线程结束
		t1.th.join();
		t2.th.join();
		t3.th.join();
                System.out.println(t1.th.isAlive());
                System.out.println(t2.th.isAlive());
                System.out.println(t3.th.isAlive());
                System.out.println("child Thread end ...");
		System.out.println("main Thread end ...");
	}

}
class MyThread1 implements Runnable{

	public Thread th;
	public MyThread1(String threadName) {
		th=new Thread(this, threadName);
		System.out.println("开始调用线程名称为"+threadName+"的start()方法");
		th.start();
	}
	@Override
	public void run() {
		try {
			for(int i=1;i<=5;i++){
				th.sleep(1000);//让子线程睡眠1秒
				System.out.println("大家好,我是线程名称为"+th.getName()+"的:"+i);
			}
			//捕获sleep()方法可能抛出的异常
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

主线程启动了三个子线程,让三个子线程一同运行,进而调用各自的join()方法等待它们线程结束,然后才让主线程结束。

开始调用线程名称为child Thread One的start()方法
开始调用线程名称为child Thread Two的start()方法
开始调用线程名称为child Thread Three的start()方法
大家好,我是线程名称为child Thread One的:1
大家好,我是线程名称为child Thread Three的:1
大家好,我是线程名称为child Thread Two的:1
大家好,我是线程名称为child Thread Three的:2
大家好,我是线程名称为child Thread One的:2
大家好,我是线程名称为child Thread Two的:2
大家好,我是线程名称为child Thread Three的:3
大家好,我是线程名称为child Thread One的:3
大家好,我是线程名称为child Thread Two的:3
大家好,我是线程名称为child Thread Two的:4
大家好,我是线程名称为child Thread One的:4
大家好,我是线程名称为child Thread Three的:4
大家好,我是线程名称为child Thread One的:5
大家好,我是线程名称为child Thread Three的:5
大家好,我是线程名称为child Thread Two的:5
false
false
false
child Thread end ...
main Thread end ...


线程优先级的作用

在第一节中,我们提到了通过setPriority(int level);来设置线程优先级,那么线程的优先级在线程运行过程中有什么用呢。

线程优先级被线程调度用来判断何时每个线程允许运行。理论上,优先级高的线程比优先级低的线程获得更多的CPU时间。实际上,线程获得的CPU时间通常由包括优先级在内的多个因素决定(例如,一个实行多任务处理的操作系统如何更有效的利用CPU时间)。

一个优先级高的线程自然比优先级低的线程优先。举例来,当低优先级的线程正在运行,而一个高优先级的线程被恢复(例如从睡眠中或等待I/O中),它将抢占低优先级线程所使用的CPU。

设置线程的优先级,用setPriority(int level)方法,该方法属于Thread类,它的通常格式为:

public final void setPriority(int newPriority);

这里level指定了对所调用线程的新的优先级的设置。level的值必须在1-10之间,否则会抛出IllegalArgumentException异常。

下面看一个例子:

public class Test4 {

    public static void main(String[] args) throws InterruptedException {
        
        MyThread2 t1=new MyThread2(3);
        MyThread2 t2=new MyThread2(7);
        
        t1.start();
        t2.start();
        Thread mainThread=Thread.currentThread();
        mainThread.sleep(1000);//主线程睡眠1秒
        t1.stop();
        t2.stop();
        t1.th.join();
        t2.th.join();
        
        System.out.println("One:"+t1.number);
        System.out.println("Two:"+t2.number);
        
    }

}
class MyThread2 implements Runnable {

    public Thread th = null;
    private volatile static boolean FLAG = true;
    public int number=0;
    
    public MyThread2(int level) {
        th=new Thread(this);
        th.setPriority(level);//设置优先级
    }
    
    @Override
    public void run() {
        while(this.FLAG){
            number++;
        }
    }
    public void stop(){
        this.FLAG = false;
    } 
    public void start(){
        th.start();
    }
    
}

在主线程中创建两个子线程,并把它们的优先级设置为3和7。两个线程被允许启动1秒。每个线程执行一个循环,1秒后,主线程终止了两个子线程。

运行结果:

One:558355176
Two:197268901

可以看出线程确实上下转换,甚至不屈从于CPU,也不被输入输出阻塞,优先级高的线程大约获得了80%的CPU时间。

上述程序还有个值得注意的地方,注意FLAG前的关键字volatile。用在此处以确保FLAG的值在下面的循环中每次得到验证。

while(this.FLAG){
    number++;
}
如果不用volatile,Java可以自由的优化循环;FLAG的值被存在CPU的一个寄存器中,每次重复不一定需要复检。volatile的运用阻止了该优化,告知Java FLAG可以被改变,以确保FLAG的值在循环中每次得到验证。

猜你喜欢

转载自blog.csdn.net/xkfanhua/article/details/80585778