Java并发--sleep()、wait()、notify()、notifyAll()方法
sleep()和wait方法比较
基本差别:
1,sleep是Thread类中的native方法、wait是Object类中的方法。
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
/**
* Causes the current thread to wait until it is awakened, typically
* by being <em>notified</em> or <em>interrupted</em>.
* <p>
* In all respects, this method behaves as if {@code wait(0L, 0)}
* had been called. See the specification of the {@link #wait(long, int)} method
* for details.
*
* @throws IllegalMonitorStateException if the current thread is not
* the owner of the object's monitor
* @throws InterruptedException if any thread interrupted the current thread before or
* while the current thread was waiting. The <em>interrupted status</em> of the
* current thread is cleared when this exception is thrown.
* @see #notify()
* @see #notifyAll()
* @see #wait(long)
* @see #wait(long, int)
*/
public final void wait() throws InterruptedException {
wait(0L);
}
2,sleep方法可以在任何地方使用,wait方法只能在synchronized方法或者synchronized块中使用。
主要区别:
1,Thread.sleep 只会让出cpu,不会导致锁行为改变。
2,Object.wait 不仅会让出cpu,还会释放占用的同步资源锁。其他线程可以得到锁。
wait传
demo:
public class WaitSleepDemo {
public static void main(String[] args) {
final Object lock = new Object();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread A is waiting to get lock");
synchronized (lock){
try {
System.out.println("thread A get lock");
Thread.sleep(20);
System.out.println("thread A do wait method");
lock.wait(1000); //等待1000ms,让出cpu、锁
System.out.println("thread A is done");
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}).start();
try{
Thread.sleep(10);
} catch (InterruptedException e){
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread B is waiting to get lock");
synchronized (lock){
try {
System.out.println("thread B get lock");
System.out.println("thread B is sleeping 10 ms");
Thread.sleep(10);
lock.notifyAll(); // 唤醒其他所有线程,将A放入锁池当中去竞争锁,但是不释放锁,继续执行代码
Thread.yield(); //yeild 不会对锁造成影响。总是B先执行完。
Thread.sleep(2000); // 对锁没影响
System.out.println("thread B is done");
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}).start();
}
}
执行结果:
thread A is waiting to get lock
thread A get lock
thread B is waiting to get lock //A 的sleep方法不让出锁。B等待
thread A do wait method //A wait方法 让出锁,A
thread B get lock //A让出锁 B获得锁
thread B is sleeping 10 ms
thread B is done //B执行完毕
thread A is done //A的wait(1000),到期自动唤醒,正好B释放锁。A可以得到锁
可以看到,A虽然执行sleep方法,让出CPU,但不让出锁。如果不执行wait(1000)方法,B会一直等待获取锁。
wait方法,必须写在synchronized,因为必须要先获取锁,才能去释放锁。
notify(),notifyAlll()方法:
上面demo中,通过wait(1000),设置参数1000ms后,A线程会自动唤醒。
也可以直接用wait(),不设置自动唤醒,可以在B线程中使用Object.notify()唤醒A线程。
demo:
public class NotificationDemo {
private volatile boolean go = false;
public static void main(String args[]) throws InterruptedException {
final NotificationDemo test = new NotificationDemo();
Runnable waitTask = new Runnable(){
@Override
public void run(){
try {
test.shouldGo();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " finished Execution");
}
};
Runnable notifyTask = new Runnable(){
@Override
public void run(){
test.go();
System.out.println(Thread.currentThread().getName() + " finished Execution");
}
};
Thread t1 = new Thread(waitTask, "WT1"); //will wait
Thread t2 = new Thread(waitTask, "WT2"); //will wait
Thread t3 = new Thread(waitTask, "WT3"); //will wait
Thread t4 = new Thread(notifyTask,"NT1"); //will notify
//starting all waiting thread
t1.start();
t2.start();
t3.start();
//pause to ensure all waiting thread started successfully
Thread.sleep(200);
//starting notifying thread
t4.start();
}
/*
* wait and notify can only be called from synchronized method or bock
*/
private synchronized void shouldGo() throws InterruptedException {
while(go != true){
System.out.println(Thread.currentThread()
+ " is going to wait on this object");
wait(); //release lock and reacquires on wakeup
System.out.println(Thread.currentThread() + " is woken up");
}
go = false; //resetting condition
}
/*
* both shouldGo() and go() are locked on current object referenced by "this" keyword
*/
private synchronized void go() {
while (go == false){
System.out.println(Thread.currentThread()
+ " is going to notify all or one thread waiting on this object");
go = true; //making condition true for waiting thread
//notify(); // only one out of three waiting thread WT1, WT2,WT3 will woke up
notifyAll(); // all waiting thread WT1, WT2,WT3 will woke up
}
}
}
结果:
Thread[WT1,5,main] is going to wait on this object
Thread[WT3,5,main] is going to wait on this object
Thread[WT2,5,main] is going to wait on this object
Thread[NT1,5,main] is going to notify all or one thread waiting on this object
Thread[WT1,5,main] is woken up
Thread[WT2,5,main] is woken up
Thread[WT2,5,main] is going to wait on this object
NT1 finished Execution
WT1 finished Execution
Thread[WT3,5,main] is woken up
Thread[WT3,5,main] is going to wait on this object
两个概念(针对对象):
锁池entryList。会去竞争锁。若B线程被阻塞,进入该对象的锁池,等待锁的释放,去竞争锁。如果多个不同优先级的线程竞争锁,优先级高获取锁的概率大。
等待池WaitSet。不会去竞争锁。A调用wait()方法,会释放该对象的锁,同时进入等待池中,不竞争锁。
yield)()方法:
当调用该函数时,调度器会给线程调度器一个 当前线程愿意出让CPU使用的暗时,但是线程调度器可能会忽略。
A hint to the scheduler that the current thread is willing to yield
its current use of a processor. The scheduler is free to ignore this
hint.
会让出当前现线程CPU,但不会改变锁的状态。
如何中断线程
直接使用stop()可能会导致异常,不推荐。
调用interrupt(),通知线程应该中断了。
如果是:阻塞线程,会退出并抛出InterruptException异常;正常运行线程,会将中断标志位 设置为true,继续运行。
demo:
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Runnable interruptTask = new Runnable() {
@Override
public void run() {
int i = 0;
try {
//在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(100); // 休眠100ms
i++;
System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") loop " + i);
}
} catch (InterruptedException e) {
//在调用阻塞方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。)
System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") catch InterruptedException.");
}
}
};
Thread t1 = new Thread(interruptTask, "t1");
System.out.println(t1.getName() +" ("+t1.getState()+") is new.");
t1.start(); // 启动“线程t1”
System.out.println(t1.getName() +" ("+t1.getState()+") is started.");
// 主线程休眠300ms,然后主线程给t1发“中断”指令。
Thread.sleep(300);
t1.interrupt();
System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");
// 主线程休眠300ms,然后查看t1的状态。
Thread.sleep(300);
System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
}
}
运行结果:
t1 (NEW) is new.
t1 (RUNNABLE) is started.
t1 (RUNNABLE) loop 1
t1 (RUNNABLE) loop 2
t1 (RUNNABLE) catch InterruptedException. //线程调用sleep方法处于阻塞状态,调用interrupt方法,catch到异常后抛出异常。
t1 (TIMED_WAITING) is interrupted. //t1会不断检查中断标志位
t1 (TERMINATED) is interrupted now. // 已经被中断
总结:interrupt() 并不能主动中断线程,运行时会主动检查标志位,如果是true,自行停止线程。
posted on 2023-05-25 23:39 passionConstant 阅读(46) 评论(0) 编辑 收藏 举报