更新时间:2021-02-02 17:22:49 来源:极悦 浏览995次
线程(thread)是操作系统能够进行运算调度的最小单位,也是独立调度和分派的基本单位。线程作为计算机技术中十分重要的内容,线程是我们必须要掌握的重点知识。在线程中的许多操作,比如终止线程都是需要调用线程操作方法来实现的,本文我们通过一些实例来介绍这些线程操作方法。
我们比较熟悉的一些线程操作方法:
Thread.currentThread().getName();获取当前运行线程的名字
suspend:暂停线程后不释放锁,容易造成死锁
stop:线程被粗暴终结,的资源不能释放
interrupt:通知线程可以结束,线程可以完全不理会, 结合isInterrupted使用
注意interrupted方法和isInterrupted的区别,前者会在调用后清除interrupted status,后者不会。
中断线程不建议自主设置标志位,因为如果是通过判断标志位进入线程sleep、wait、take等方法,线程被阻塞,就不会再判断标志位,而使用interrupt就不会产生这样的问题,因为他们可以自动监控线程中断状态。(如果是在runnable中想使用这个方法,就使用Thread.currentThread.isInterrupted即可)
使用interrupt中断线程
public class HasInterruptException extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()) {
System.out.println(Thread.currentThread().getName() + "is running");
}
System.out.println(Thread.currentThread().getName() + "interrupt flag is " + isInterrupted());
}
public static void main(String[] args) {
HasInterruptException hasInterruptException = new HasInterruptException();
hasInterruptException.start();
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
hasInterruptException.interrupt();
}
}
线程阻塞方法也可以监控线程interrput方法,如果处于阻塞状态,会被程序检测出来,并抛出interruptedException异常,同时将interrupt状态恢复,但线程会继续运行剩余的任务
public class HasInterruptException extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()) {
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "is running");
System.out.println(Thread.currentThread().getName() + "now interrupt state " + isInterrupted());
}
System.out.println(Thread.currentThread().getName() + "interrupt flag is " + isInterrupted());
}
public static void main(String[] args) {
HasInterruptException hasInterruptException = new HasInterruptException();
hasInterruptException.start();
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
hasInterruptException.interrupt();
}
}
如果需要在有阻塞代码时也能正常中断线程,需要在阻塞方法检查到中断时再添加中断方法,在interrupt()之前可以添加一些善后处理代码
@Override
public void run() {
super.run();
while (!isInterrupted()) {
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
//如果需要在有阻塞代码时也能正常中断线程,需要在阻塞方法检查到中断时再添加中断方法,在此之前可以添加一些善后处理代码
interrupt();
}
System.out.println(Thread.currentThread().getName() + "is running");
System.out.println(Thread.currentThread().getName() + "now interrupt state " + isInterrupted());
}
System.out.println(Thread.currentThread().getName() + "interrupt flag is " + isInterrupted());
}
由此可知,阻塞方法中检测到中断会抛出异常到原因是为了提示程序这时候线程不能直接中断,需要正确处理善后,再执行中断。
start:Thread仅仅是一个线程相关类,new出来后不调用start方法是没有开启线程的。
start方法只能调用一次,多次调用会抛出IllegalThreadStateException异常
如果new一个Thread之后直接调用run方法,和调用一个普通方法效果完全一致,在主线程中执行。
yield:执行该方法的线程会让出cpu的执行权,进入就绪状态。不会释放锁,调用该方法后cpu可能还会重新选中该线程执行,所以这个方法不可靠。
join:让调用该方法的线程执行完毕之后,其他线程才能执行,必须放在start之后。有三个重载方法,参考 Java Thread的join() 之刨根问底
static class A extends Thread {
@Override
public void run() {
super.run();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " runing end");
}
}
public static void main(String[] args) {
A a = new A();
A aa = new A();
a.start();
aa.start();
try {
aa.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setPriority:设置线程优先级,这个方法不完全可靠,也有一定效果
setDaemon(boolean)守护线程,当进程中所有线程都是守护线程时候,进程结束
守护线程因为用户线程结束而被动结束时候,线程中的方法不一定能完全执行,如finally语句不一定能执行
notify()/notifyAll() 不会释放锁
注: wait(),notify(),notifyAll()应该放在synchronized关键字所保护的内容内,wait方法调用时调用方释放锁,但是notify/notifyAll调用时调用方需要在线程方法运行完毕之后才释放锁,所以notify/notifyAll一般会被放在同步代码块的最后一行。
wait() wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁,可以在notfiy方法后增加一个等待和一些代码),调用wait方法的线程就会解除wait状态并争抢cpu使用权,抢到了之后才会执行wait之后的代码。可以指定停止的时间参数,也可不指定。
sleep() sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。当休眠时间到并跑完同步代码之后才会释放锁。和wait一样,调用时候都会把cpu资源让出。
注:obj=null 只是表示这个引用不再指向该对象,不代表这个对象不存在了
PDD pp = new PDD();
PDD ppp = pp;
System.out.println(pp);
System.out.println(ppp);
pp = null;
System.out.println(pp);
System.out.println(ppp);
输出
//com.example.annotation.PDD@6d06d69c
//com.example.annotation.PDD@6d06d69c
//null
//com.example.annotation.PDD@6d06d69c
想让对象被垃圾回收机制回收,需要保证没有强引用指向这个对象
注:线程同步阻塞的一个例子
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + " start");
synchronized (this) {
try {
System.out.println(Thread.currentThread().getName() + "sleep start");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "sleep end");
}
System.out.println(Thread.currentThread().getName() + " continue...");
}
}
所有遇到同步代码块或者同步方法的线程都会被阻塞,除非抢到锁,抢到锁之后会继续往下执行,而不会跳过同步代码块/同步方法再执行。
以上就是一些线程操作方法的实例讲解,线程操作方法的掌握不仅仅是用来实现线程的各种操作,对于我们加深理解线程的工作原理和线程中的各种机制也有很大的帮助。在本站的多线程教程中,对线程的操作方法还有更多的解读和介绍,感兴趣想要在多线程领域学有所成的小伙伴不要错过哦。
0基础 0学费 15天面授
Java就业班有基础 直达就业
业余时间 高薪转行
Java在职加薪班工作1~3年,加薪神器
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习