Thread和Object类中的重要方法详解
方法概览
wait、notify、notifyAll
作用、用法:阻塞阶段、唤醒阶段、遇到中断
- 直到以下四种情况之一发生时,才会被唤醒
- 另一个线程调用这个对象的notify()方法且刚好被唤醒的是本线程
- 另一个线程调用这个对象的notifyAll()方法
- 过了wait(long timeout)规定的超时时间,如果传入0就是永久等待;
- 线程自身调用了interrupt()
代码演示:展示wait和notify的基本用法
- 研究代码执行顺序
- 证明wait释放锁
public class Wait {
public static Object object = new Object();
static class Thread1 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + "开始执行了");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "获取到了锁。");
}
}
}
static class Thread2 extends Thread {
@Override
public void run() {
synchronized (object) {
object.notify();
System.out.println("线程" + Thread.currentThread().getName() + "调用了notify()");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.start();
Thread.sleep(200);
thread2.start();
}
}
代码演示:3个线程,线程1和线程2首先被阻塞,线程3唤醒它们。notify、notifyAll、start先执行不代表线程先启动。
public class WaitNotifyAll implements Runnable {
private static final Object resourceA = new Object();
public static void main(String[] args) throws InterruptedException {
Runnable r = new WaitNotifyAll();
Thread threadA = new Thread(r);
Thread threadB = new Thread(r);
Thread threadC = new Thread(() -> {
synchronized (resourceA) {
// resourceA.notifyAll();
resourceA.notify();
System.out.println("ThreadC notified.");
}
});
threadA.start();
threadB.start();
Thread.sleep(200);
threadC.start();
}
@Override
public void run() {
synchronized (resourceA) {
System.out.println(Thread.currentThread().getName()+" got resourceA lock.");
try {
System.out.println(Thread.currentThread().getName()+" waits to start.");
resourceA.wait();
System.out.println(Thread.currentThread().getName()+"'s waiting to end.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
代码演示:证明wait只释放当前的那把锁
public class WaitNotifyReleaseOwnMonitor {
private static volatile Object resourceA = new Object();
private static volatile Object resourceB = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (resourceA) {
System.out.println("ThreadA got resourceA lock.");
synchronized (resourceB) {
System.out.println("ThreadA got resourceB lock.");
try {
System.out.println("ThreadA releases resourceA lock.");
resourceA.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread thread2 = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (resourceA) {
System.out.println("ThreadB got resourceA lock.");
System.out.println("ThreadB tries to resourceB lock.");
synchronized (resourceB) {
System.out.println("ThreadB got resourceB lock.");
}
}
});
thread1.start();
thread2.start();
}
}
原理
- 必须拥有monitor锁
- notify只能唤醒一个
- 属于Object类
- 类似功能的Condition
- 同时持有多个锁的情况
sleep
- 作用:只想让线程在预期的时间执行,其他时候不要占用CPU资源
- 不释放锁,包括synchronized和lock锁,和wait不同
代码演示:展示线程sleep的时候不释放synchronized的monitor,等sleep时间到了以后,正常结束后才释放锁
public class SleepDontReleaseMonitor implements Runnable {
public static void main(String[] args) {
SleepDontReleaseMonitor sleepDontReleaseMonitor = new SleepDontReleaseMonitor();
new Thread(sleepDontReleaseMonitor).start();
new Thread(sleepDontReleaseMonitor).start();
}
@Override
public void run() {
syn();
}
private synchronized void syn() {
System.out.println("线程" + Thread.currentThread().getName() + "获取到了monitor。");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "退出了同步代码块");
}
}
sleep方法的特点:sleep方法可以让线程进入Waiting状态,并且不占用CPU资源,但是不释放锁,直到规定时间后再执行,休眠期间如果被中断,会抛出异常并清除中断状态。
sleep更优雅的实现方案:TimeUnit.SECONDS.sleep()
join
作用:因为新的线程加入了我们,所以我们要等他执行完再出发
用法:主线程等待加入的子线程,注意谁等谁
封装的工具类:CountDownLatch或CyclicBarrier类
join期间主线程处于什么状态:WAITING状态
代码演示:演示join,注意语句输出顺序,会变化。
public class Join {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "执行完毕");
});
Thread thread2 = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "执行完毕");
});
thread.start();
thread2.start();
System.out.println("开始等待子线程运行完毕");
thread.join();
thread2.join();
System.out.println("所有子线程执行完毕");
}
}
yield
作用:释放我的CPU时间片
定位:JVM不保证遵循
yield和sleep区别:是否随时可能再次被调度
Thread.currentThread()
作用:当前线程,可打印出当前线程的线程名字、ID等等
start、run
前面文章有介绍过了!
stop、suspend、resume
这些方法已经弃用!
来源:CSDN
作者:木兮同学
链接:https://blog.csdn.net/qq_36221788/article/details/102772541