Thread类方法解析
介绍
class Thread implements Runnable
,Thread类继承Runnable,重写了run方法
1. 构造方法Thread(Runnable target)
接收一个Runnable类型的对象,赋值给Thread类属性private Runnable target;
2. start()/run()
start()
是开启一个线程执行run()
方法的内容,如果直接调用run()方法不会开启线程,只会执行run()方法的内容。
run方法源码:
@Override
public void run() {
if (target != null) {
target.run();
}
}
默认情况下:如果target不为空,执行target.run(),也就是构造函数中的Runnable对象
/**
* 开启一个线程
*/
@Test
public void test01() {
Thread thread = new Thread();
//thread.run();//不能开启一个线程,是Runnable的接口的实现
thread.start();
}
/**
* 1.重写run方法
*
* @throws Exception
*/
@Test
public void test02() throws Exception {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("my first thread");
}
};
thread.start();
}
3. stop()终止线程
stop()方法会强制把执行到一半的线程终止,可能会造成数据问题,不推荐使用
@Test
public void test04() {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("my first thread");
}
};
thread.stop(); //不推荐使用,直接中断线程
}
4. 线程中断
线程中断是一种重要的线程协作机制,并不会立即使线程退出,而是设置一个中断标志,而如何处理,完全由线程自行决定。
与线程中断有关的有三个方法:
public void interrupt() //中断线程,设置中断标志位
public boolean isInterrupted() //判断是否中断
public static boolean interrupted() //判断是否中断,并清除当前中断状态
下面代码,设置中断标志,程序自己处理退出,若不处理中断,程序也会一直执行下去
@Test
public void test05() throws Exception {
Thread thread = new Thread(() -> {
while (true) {
//判断线程是否被中断
if (Thread.currentThread().isInterrupted()) {
System.out.println("interruted");
break;
}
Thread.yield();
}
});
thread.start();
Thread.sleep(2000);
//中断线程
thread.interrupt();
thread.join();
}
5. sleep()
public static native void sleep(long millis)
sleep()方法可以设置让线程休眠若干时间,他会抛出一个InterruptedException
异常,这个异常不是运行时异常,必须捕获。当线程sleep()时,如果中断,就会抛出这个异常。
sleep()方法由于中断而抛出异常,它会清除中断标记,故在异常处理中,若自己有捕获中断的逻辑,需要再次设置中断标志
@Test
public void test06() throws Exception {
Thread thread = new Thread(() -> {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("interruted");
break;
}
try {
System.out.println("1");
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("interruted when sleep");
//设置中断状态,抛出中断后,这里会清除中断标记位
//所以线程不会停止,if判断一直为false
Thread.currentThread().interrupt();
}
}
});
thread.start();
Thread.sleep(500);
thread.interrupt();
Thread.sleep(8000);
}
6. wait()/notify()/notifyAll()
为了支持多线程之间协作,jdk提供了两个非常重要的方法wait()、notify(),这两个方法是Object类中的,也就是所有对象都可以调用。
如果一个线程调用了object.wait(),那么这个线程就会进入object对象的等待队列,这个队列中可能有多个线程,当object.nofity()调用时,会在等待队列中随机选择一个线程将其唤醒,这个选择是随机的。nofityAll()会唤醒等待队列中的所有线程。
object.wait()方法、notify()方法、notifyAll()方法必须在synchronized语句中,需要获得目标对象监视器。wait()方法执行后会释放监视器,wait()方法被唤醒后,还需要等待notify()所在的synchronized语句释放监视器,重新获得object的监视器后,才可以继续执行。
sleep()方法不会释放任何资源
@Test
public void test12() throws Exception {
Object object = new Object();
Thread t1 = new Thread(() -> {
synchronized (object) {
System.out.println("t1 starting");
try {
object.wait();//释放锁 等待唤醒 再获得锁,方可执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 end");
}
});
Thread t2 = new Thread(() -> {
synchronized (object) {
System.out.println("t2 starting");
object.notify();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2 end");
}
});
t1.start();
t2.start();
/**
* t1 starting
* t2 starting
* t2 end
* t1 end
*/
Thread.sleep(5000);
}
7. suspend()/resume()
suspend()挂起线程,resume()继续执行,已经不推荐使用。
- suspend()在导致线程暂停的同时,并不会释放任何资源,这样会阻塞在相关锁上其它线程的执行
- 如果resume()意外在suspend()前就执行了,被挂起的线程就会一直挂起,锁也一直不会释放
- suspend()执行后被挂起的线程依旧是Runnable状态,这会严重影响我们对系统当前状态的判断
@Test
public void test07() throws Exception {
Object o = new Object();
Thread thread = new Thread(() -> {
synchronized (o) {
try {
Thread.sleep(2000);
Thread.currentThread().suspend();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
//造成线程还没有暂停,就执行唤醒了,线程会一直暂停下去,不会终止
//被锁住的资源也将会一直锁住
thread.resume();
thread.join();
}
8. join()/yield()
线程之间协作的另一种方式
join()会一直阻塞在当前线程,知道目标线程完成,当然可以设置一个最大等待时间。join()的本质是调用线程的wait()方法,被调用线程在退出前会调用notifyAll()方法通知所有等待的线程。所以不要在Thread对象实例上调用wait()或者notify()等方法,可能会影响系统api工作
yeild()是让出当前cpu执行权,但是还会去争夺cpu资源,也就是还有可能再次抢到。
9. setPriority()
设置线程优先级1-10
jdk中默认设置了三种
/**
* The minimum priority that a thread can have.
*/
public static final int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public static final int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public static final int MAX_PRIORITY = 10;
10. setDaemon()
设置是否为后台线程,线程分为后台线程与用户线程,
后台线程比如:垃圾回收线程,jit线程等
后台线程是为用户线程服务的,若用户线程执行完毕,后台线程也会死亡。
@Test
public void test09() throws Exception {
Thread t = new Thread(() -> {
try {
while (true) {
System.out.println(1);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t.setDaemon(true);
t.start();
}