1 Thread
和Object
类中的重要方法详解
1.1 sleep
方法详解
- 作用:让线程在预期的世界执行,其他时候不要占用CPU资源
特点:
- 不释放锁,包括
synchronized
和lock
- 和
wait
不同
/**
* @Description 展示sleep的时候不释放synchronized的monitor,等sleep时间到了以后,正常结束后才释放锁
* @Author tzb
* @Date 2021/2/9 15:43
* @Version 1.0
**/
public class SleepDontReleaseMonitor implements Runnable{
@Override
public void run() {
sync();
}
private synchronized void sync(){
System.out.println(Thread.currentThread().getName() + " 获取了monitor");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 退出了同步代码块");
}
public static void main(String[] args) {
SleepDontReleaseMonitor monitor = new SleepDontReleaseMonitor();
new Thread(monitor).start();
new Thread(monitor).start();
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Description 演示sleep不释放lock(lock需要手动释放)
* @Author tzb
* @Date 2021/2/9 15:51
* @Version 1.0
**/
public class SleepDontReleaseLock implements Runnable {
private static final Lock lock = new ReentrantLock();
@Override
public void run() {
lock.lock();
System.out.println(Thread.currentThread().getName() + " 获取到了锁");
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + " 已经苏醒");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
SleepDontReleaseLock lock = new SleepDontReleaseLock();
new Thread(lock).start();
new Thread(lock).start();
}
}
1.2 sleep
方法响应中断
- 抛出
InterruptedException
- 清除中断状态
sleep
方法可以让线程进入waiting
状态,并且不占用CPU资源,但是不释放锁,直到规定时间后再执行,休眠期间如果被中断,会抛出异常并清除中断状态。
第二种写法(更加优雅)
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* @Description 每隔1s输出当前时间,被中断
* Thread.sleep()
* TimeUnit.SECONDS.sleep()
* @Author tzb
* @Date 2021/2/9 16:05
* @Version 1.0
**/
public class SleepInterrupted implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(new Date());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("我被打断了");
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new SleepInterrupted());
thread.start();
Thread.sleep(6500);
thread.interrupt();
}
}
1.3 sleep
方法常见面试问题
1.4 join
方法
- 作用:以为新的线程加入了,所以要等待他执行完再出发。
- 用法:main 等待 thread1 执行完毕,注意谁等谁
1.4.1 普通方法
/**
* @Description 演示join,注意语句输出顺序,会变化
* @Author tzb
* @Date 2021/2/10 14:04
* @Version 1.0
**/
public class Join {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 执行完毕");
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 执行完毕");
}
});
thread1.start();
thread2.start();
System.out.println("开始等待子线程运行完毕");
thread1.join();
thread2.join();
System.out.println("所有子线程执行完毕");
}
}
1.4.2 遇到中断
/**
* @Description join期间被中断的效果
* @Author tzb
* @Date 2021/2/10 14:12
* @Version 1.0
**/
public class JoinInterrupt {
public static void main(String[] args) {
final Thread mainThread = Thread.currentThread();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
mainThread.interrupt();
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + " 执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
System.out.println("等待子线程运行完毕");
try {
thread1.join();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 主线程被中断了");
e.printStackTrace();
}
System.out.println("子线程已经运行完毕");
}
}
- 一旦在 join期间被打断,应该在处理这个中断异常的时候把子线程的内容都停止,否则就会出现不一致的情况。
public class JoinInterrupt {
public static void main(String[] args) {
final Thread mainThread = Thread.currentThread();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
mainThread.interrupt();
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + " 执行完毕");
} catch (InterruptedException e) {
System.out.println("子线程中断");
}
}
});
thread1.start();
System.out.println("等待子线程运行完毕");
try {
thread1.join();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 主线程被中断了");
// 把中断传递给子线程
thread1.interrupt();
}
System.out.println("子线程已经运行完毕");
}
}
1.4.3 在 join 期间,线程到底是什么状态? Waiting
public class JoinThreadState {
public static void main(String[] args) throws InterruptedException {
final Thread mainThread = Thread.currentThread();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println(mainThread.getState());
System.out.println(Thread.currentThread().getName() + " 运行结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
System.out.println("等待子线程运行完毕");
thread.join();
System.out.println("子线程运行完毕");
}
}
- debug方式
1.4.4 join注意点
- 工具类
CountDownLatch
或者CyclicBarrier
join 源码
- join内部没有一个
notify
- 是谁执行了唤醒的操作,JVM层
- 每一个 Thread 类在
run
方法运行结束后, 会自动执行类似notify
操作 - 在讲
wait
时,不提倡用Thread
类进行wait
1.4.5 join的等价代码
/**
* @Description join的代替写法
* @Author tzb
* @Date 2021/2/10 14:57
* @Version 1.0
**/
public class JoinPrinciple {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 执行完毕");
}
});
thread1.start();
System.out.println("开始等待子线程运行完毕");
//thread1.join();
synchronized (thread1){
thread1.wait();
}
System.out.println("所有子线程执行完毕");
}
}
1.4.6 join方法的常见面试问题
- 在 join 期间,线程处于哪种线程状态?(
waiting
)