一、sleep
- Thread类的静态方法
- 当前线程由RUNNABLE状态的会进入TIMED_WAITING(超时等待);
- 超时等待过程中线程持有的锁并不会释放;
1、API
Thread.sleep(long millis); // 单位:毫秒
Thread.sleep(long timeout, int nanos); // 毫秒,纳秒
或
TimeUnit.SECONDS.sleep(long timeout); // 这个时间单位可以优选,底层调用的其实还是Thread.sleep(ms, ns);
2、示例
public class ThreadOperation {
static Object lock = new Object();
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println("已进入线程 " + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 睡会,切换到主线程,看看主线程能不能拿到锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " is end");
}
});
thread.start();
try {
Thread.sleep(1000); // 睡会,保证进入子线程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("哈哈哈");
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " is end");
}
}
}
结果:可以看到,子线程超时等待时并不会释放锁
已进入线程 Thread-0
哈哈哈
Thread-0 is end
main is end
二、wait
- Object类的方法,使用时必须是已经获得锁(lock.wait())
- 当前线程由RUNNABLE状态的会进入WAITING或TIMED_WAITING(超时等待)状态;
- 等待过程会释放锁资源,直到被唤醒(notify()/notifyAll())或是超时结束后会再去争夺资源
1、API
wait(); // 需要使用notify()或notifyAll()唤醒等待该锁的线程
wait(long timeout); // 毫秒,等待一定的时间
wait(long timeout, int nanos); // 毫秒,纳秒
2、示例1
wait(long timeout);
public class ThreadOperation {
static Object lock = new Object();
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println("已进入线程 " + Thread.currentThread().getName());
try {
lock.wait(1000); // 此线程释放锁加入等待队列, 1s后又争夺资源
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is end");
}
}
});
thread.start();
try {
Thread.sleep(300); // 睡会,保证进入子线程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("哈哈哈");
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " is end");
}
}
}
结果:可以看到,子线程超时等待时释放了锁
已进入线程 Thread-0
哈哈哈
main is end
Thread-0 is end
3、示例2
监视器wait()后当前线程进入WAITTING状态
wait() 配合notify() 或notifyAll()使用,详见另一blognotify() 和 notifyAll()方法的使用和区别
三、stop(已弃用)
- stop()调用后finally中的代码还会执行,当前线程立即终止并释放一切资源;
- 这就会不安全,因为它在终止一个线程时会强制中断线程的执行,不管run方法是否执行完了,并且还会释放这个线程所持有的所有的锁对象。这一现象会被其它因为请求锁而阻塞的线程看到,使他们继续向下执行。这就会造成数据的不一致。
- 例如:从A账户向B账户转账500元,这一过程分为三步,第一步是从A账户中减去500元,假如到这时线程就被stop了,那么这个线程就会释放它所取得锁,然后其他的线程继续执行,这样A账户就莫名其妙的少了500元而B账户也没有收到钱。这就是stop方法的不安全性
public class ThreadDemo implements Runnable{
static Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(new ThreadDemo(), "thread-a");
Thread thread2 = new Thread(new ThreadDemo(), "thread-b");
thread1.start();
thread2.start();
try {
TimeUnit.SECONDS.sleep(1); // 睡会,让走到子线程
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 获得了锁");
try {
Thread.currentThread().stop();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + " stop()");
System.out.println("唤醒所有持有lock锁的线程");
lock.notifyAll();
}
}
System.out.println(Thread.currentThread().getName() + " end"); // 因为被强行终止,所以不会执行这行代码
}
@Override
public void run() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 获得了锁");
try {
System.out.println(Thread.currentThread().getName() + " wait()");
lock.wait();
System.out.println(Thread.currentThread().getName() + " end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
结果:可以看到主线程被强行终止后,finally中代码还会执行,但不会再往下走;锁被释放后被唤醒持有该锁的所有子线程又继续获得锁走下去
thread-a 获得了锁
thread-a wait()
thread-b 获得了锁
thread-b wait()
main 获得了锁
main stop()
唤醒所有持有lock锁的线程
thread-b end
thread-a end
四、suspend(已弃用)
- 当前线程调用suspend()后后立即挂起,线程状态还是RUNNABLE,不会释放锁资源,这就会很容导致死锁(这也是弃用它的原因);
- 实质是由RUNNING运行中转为RUNNABLE(可运行,等待线程调度再次给到cpu资源),只不过Thread的统称这两种都为RUNNABLE;
public class ThreadDemo implements Runnable{
static Object lock = new Object();
public static void main(String[] args) {
Thread thread = new Thread(new ThreadDemo());
thread.start();
try {
TimeUnit.SECONDS.sleep(1); // 睡会,让走到子线程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("resume前" + thread.getName() + "状态是 " + thread.getState()); // 2
thread.resume();
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 获得了锁"); // 4
}
System.out.println(Thread.currentThread().getName() + " end"); // 5
}
@Override
public void run() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 获得了锁"); // 1
Thread.currentThread().suspend();
System.out.println(Thread.currentThread().getName() + " end"); // 3
}
}
}
结果
Thread-0 获得了锁
resume前Thread-0状态是 RUNNABLE
Thread-0 end
main 获得了锁
main end