线程2——线程的常用方法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/YJT180/article/details/100044329
  • 线程常用方法

  • Join方法

join方法:执行该方法的线程进入阻塞状态,直到调用该方法的线程结束后再由阻塞转为就绪状态

 要注意的一点就是:执行方法的线程与调用方法的线程并不是一个概念,例如在图片中我们看到,计数器线程本应该循环输出的,但是在i=2时执行了join方法,而join方法由时间线程调用,此时计数器线程便进入了阻塞状态,转而时间线程进入了运行状态。开始循环输出,直到其执行完毕,计数器线程再次转为就绪状态,由于此时没有其他线程,就顺利转为运行状态,继续输出直到结束。

值得注意的是:线程对象在调用join方法前必须先调用start方法,否则该线程永远不会进入执行状态。

 在这段代码中,由于时间线程并没有先调用start方法,没有开始启动,因此无法调用join方法,原因在后面会提及

  • interrupt方法

interrupt方法:结束线程在调用Object类的wait方法或该类的join方法、sleep方法过程中的阻塞状态,并在调用waitjoinsleep方法处产生InterruptedException异常。

在这段代码中,由于我们在时间线程的run方法中植入了休眠代码,本来是应该直到30秒后才输出afterTime,但主线程中的时间线程对象调用了interrupt方法,使得休眠导致的阻塞状态终止,于是afterTime便被输出,同时由于sleep被try-catch包裹,其终止导致了异常被捕获。

  • currentThread方法 

currentThread方法:返回当前正在执行的线程对象

我们来区别一下几段代码

public class Test {

	public static void main(String[] args) {
		Thread thread = new TimeThread();
		System.out.println(thread);  
		thread.start();
	}
}

class TimeThread extends Thread{

	@Override
	public void run() {
		Thread thread = Thread.currentThread();//返回的是时间线程
		System.out.println(thread);
	}
}
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {

	public static void main(String[] args) {
		new TimeThread().start();
	}
}

class TimeThread extends Thread{

	public TimeThread(){
		super("时间线程");
	}
	
	@Override
	public void run() {
		printTime();
	}
	
	public void printTime(){
		Thread thread = Thread.currentThread();//返回时间线程
		String time = new SimpleDateFormat("HH:mm:ss").format(new Date());
		System.out.println(thread.getName()+",当前时间:"+time);
	}
}
public class Test {

	public static void main(String[] args) {
		TimeThread timeThread = new TimeThread();
		System.out.println("########"+timeThread);
		timeThread.start();//返回时间线程
		
		timeThread.run();//返回主线程
	}
}

class TimeThread extends Thread{

	@Override
	public void run() {
		Thread thread = Thread.currentThread();
		System.out.println("@@@@@@@@"+thread);
	}
}

为什么结果是这样呢?这里我们又要弄明白“执行”某个方法的概念了,像第一段代码中的thread.start();,代表着主程序执行了start方法,而start方法是由时间线程对象调用的,不是它在执行,而这个对象执行的,是其所在类的run方法,由于run方法中有currentThread方法,因此这个对象就执行了这个方法,所以方法返回的就是时间线程对象;区别的一点就是最后一段代码的timeThread.run(),这里我们看到,run方法是在主程序里就执行了,因此返回的对象为主线程。

  • isAlive方法

isAlive方法:判定该线程是否处于就绪、运行或阻塞状态,如果是则返回true,否则返回false

我们要注意。isAlive方法判断的是线程是否处于就绪,运行,阻塞三种状态中的任意一种,通过线程的生命周期我们可以换言之,该方法实际上只要线程start了,且未dead,就会返回true,在上述代码中,主线程的输出语句一定是true,因为如果主线程生命周期未结束,就处于三种状态之中,如果已经结束,那么也没有输出语句了;而打印线程在start后,其run方法既有可能输出false,也有可能输出true,因为主线程和打印线程要抢占cpu的控制权,如果主线程成功获取的话,它就结束了,因此run方法返回false,如果打印线程先抢夺到控制权,此时主线程还未结束,则返回true。

前面我们提到join方法不会被一个尚未start的线程调用,这是因为join方法中就使用了isAlive方法来判断调用它的线程是否存活,未启动或已死亡的线程都是无法调用成功的

  • setDaemon方法 

setDaemon方法:用于将一个尚未调用线程start方法的线程设置为守护线程。守护线程主要用于为其他线程的运行提供服务(Java中的垃圾回收机制就是守护线程),这种线程属于创建它的线程

注意

1.守护线程随着最后一个非守护线程的终止而终止,如下代码:

在这个方法中,计数线程被设为了守护线程,并且启动,随后开始循环输出计数,随着主线程sleep结束,主线程也结束了,该程序中便不再有非守护线程存活,因此计数线程终止。

同时我们也需要注意:守护线程的终止条件是——最后一个非守护线程终止 ,因此,只要程序中尚有非守护线程,所有的守护线程都会继续存活(除非自己运行结束)。除了调用其他特殊方法,守护线程互不影响存活

,并且某个特定的非守护线程也对守护线程的存活没有影响;对守护线程存活有影响的,有且只有“最后一个存活者的非守护线程”,这个线程就是“压死守护线程的最后一棵稻草”。

  • 其他方法

void start():使该线程开始启动,Java 虚拟机负责调用该线程的 run() 方法。多次启动一个线程是非法的。

void sleep(long millis)Thread类静态方法,线程进入阻塞状态,在指定时间(单位为毫秒)到达之后进入就绪状态(Runnable),而非立即进入执行状态。

void yield():静态方法,当前线程放弃占用CPU资源,回到就绪状态,使其他优先级不低于此线程的线程有机会被执行。

这个方法值得注意的是,它是使运行状态的线程回归到就绪状态,因此原来就绪区的线程“有机会”被执行,并不代表它们一定会执行,因为这个方法也到了就绪区,可以和其他线程继续抢占cpu,如果抢占成功的话,执行的还是这个线程。

void setPriority(int newPriority):设置当前线程的优先级,线程优先级越高,线程获得执行的次数越多,Java线程的优先级用整数表示,取值范围是1~10Thread类有以下三个静态常量:

1.static int MAX_PRIORITY   最高优先级值为10

2.static int NORM_PRIORITY   默认优先级值为5

3.static int MIN_PRIORITY   最低优先级值为1

注意:同一个线程类创建的多个线程,线程优先级越高的线程获得的执行次数极有可能越多;但是不同线程类创建的线程,线程优先级越高,执行次数不一定越多,这个run方法的代码复杂度有关

 

这就好比有一条公路(程序)上有许多货车(线程)在开,通过给它们安装更好的发动机(分配更高的优先级),它们会跑得比原来快,但是不是比对方快,还要看它们的运载量大不大(run方法的复杂程度),重量太重的话,发动机再强也可能跑不过其他轻量车。

int getPriority():获得当前线程的优先级。

猜你喜欢

转载自blog.csdn.net/YJT180/article/details/100044329