线程API
线程方法API
-
start()
启动线程,线程以异步的方式来执行;
启动一次后,不可以再重复调用,否则会出现异常
-
run()
启动异步线程后,线程run方法中的内容;
如果直接调用run方法,那么run方法就相当于是一个普通方法,被他所在的那个线程调用,也就是同步执行,不会异步执行
-
state
线程状态
-
sleep
sleep方法,会让线程进入睡眠,此时线程的状态是time waiting;
其他线程可以使用interrupt方法打断正在睡眠的线程,这时sleep线程会抛出InterruptedException,sleep线程继续执行;
sleep结束的线程未必会立即得到执行;
建议使用TimeUnit的sleep代替Thread的sleep来获得更好的可读性;
-
yield
调用yield方法会让当前线程从running进入runnable就绪状态,然后调度其他线程;
注意:调用了yield方法,并不会切换到别的线程,具体的线程依赖于操作系统的任务调度
-
线程优先级setPriority
线程优先级会提示cpu调度器优先调度该线程;
如果在cpu比较忙时,优先级高的线程会获得更多的时间片,但cpu闲时,优先级几乎没有作用
-
isInterrupted
判断是否被打断,不会清除打断标记
-
isAlive
判读线程是否还存活
-
interrupt
打断线程,如果线程正在sleep, wait, join会导致被打断的线程抛出InterruptedException,并清除打断标记;
如果打断正在运行的线程,则会设置打断标记
public static void main(String[] args) { Thread thread = new Thread(()->{ try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); // 打断sleep的线程,会清除标记;打断running的线程,打断标记为false System.out.println("线程状态:" + thread.getState() + " 打断标记:" + thread.isInterrupted()); }
输出结果:
java.lang.InterruptedException at java.lang.Thread.sleep(Native Method) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) at com.mylearn.thread.Test6.lambda$main$0(Test6.java:9) at com.mylearn.thread.Test6$$Lambda$1/0x0000000000000000.run(Unknown Source) at java.lang.Thread.run(Thread.java:823) 线程状态:RUNNABLE 打断标记:false
如果打断的线程是running的状态,打断标记会被置为true,但也仅仅是将打断标记置为了true,线程仍然会继续执行。
public static void main(String[] args) { Thread thread = new Thread(()->{ while(true){ if(Thread.currentThread().isInterrupted()){ break; } System.out.println(1); } }); thread.start(); thread.interrupt(); System.out.println("线程状态:" + thread.getState() + " 打断标记:" + thread.isInterrupted()); }
-
interrupted
判断当前线程是否被打断,会清除打断标记
-
currentedThread
获取当前正在执行的线程
-
join
a线程调用b线程的join方法,a线程会等待b线程执行完后再继续执行。
static int res = 0; public static void main(String[] args) { Thread thread = new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } res = 10; }); thread.start(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(res); }
如果有多个线程时,主线程可以调用多个线程的join方法,使得main线程等待所有线程都执行完再继续执行main线程。
static int r1 = 0; static int r2 = 0; public static void main(String[] args) { Thread thread1 = new Thread(()->{ r1 = 10; try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread thread2 = new Thread(()->{ r2 = 20; try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } }); thread1.start(); thread2.start(); long start = System.currentTimeMillis(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(System.currentTimeMillis() - start); }
join方法也可以指定时间来等待。
两阶段终止模式
概念
在一个线程T1中,如何优雅的终止线程T2?
错误思路
-
使用线程的stop方法
stop方法会真正杀死进程,如果这时线程锁住了共享资源,那么当它被杀死后,再也没机会释放锁,其他线程永远无法获取锁
-
使用System.exit(1)
这种做法会让整个程序都停止。
正确思路
public static void main(String[] args) throws InterruptedException {
TwoPhaseTermination twoPhaseTermination = new TwoPhaseTermination();
twoPhaseTermination.start();
TimeUnit.SECONDS.sleep(5);
twoPhaseTermination.stop();
}
static class TwoPhaseTermination {
private Thread monitorThread;
public void start() {
monitorThread = new Thread(() -> {
while (true) {
Thread current = Thread.currentThread();
if (current.isInterrupted()) {
System.out.println("料理后事");
break;
}
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("running monitor");
} catch (InterruptedException e) {
current.interrupt();
}
}
});
monitorThread.start();
}
public void stop() {
monitorThread.interrupt();
}
}
打断park的线程
可以使用工具类LockSupport来使线程暂停,可以使用interrupt打断正在park的线程,被打断的park线程无法再次park,除非清除打断标记。
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("park...");
LockSupport.park();
System.out.println("unpark");
LockSupport.park();
System.out.println("打断标记: " + Thread.currentThread().isInterrupted());
System.out.println("打断标记: " + Thread.interrupted());
LockSupport.park();
});
t1.start();
TimeUnit.SECONDS.sleep(1);
t1.interrupt();
}
过时不推荐的方法
- stop
- suspend
- resume
主线程和守护线程
设置守护线程: setDaemon(true)