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 阅读(63) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY