线程状态&线程控制
线程状态
新建状态
new Thread() 后 该线程处于新建状态,与其他Java对象一样,未表现出线程的特征;
就绪状态
当 Thread的对象 调用了 start方法后,该线程处于 就绪状态;
JVM会为当前线程创建 运行时环境(虚拟机栈、程序计数器);
处于 就绪状态的线程 并未开始执行,需要等待CPU的调度;
运行状态
处于就绪状态的线程 获得CPU后,开始执行run方法,此时该线程处于 运行状态;
阻塞状态
如下情况,处于运行状态的线程将进入阻塞状态:
线程 主动调用 sleep方法,放弃CPU资源;
线程 调用了阻塞IO的方法,在方法返回之前,将被阻塞;
线程 试图获取同步监视器,但 该同步监视器被其他线程持有;
线程 等待某个通知(notify);
线程 主动调用suspend,将线程挂起(容易导致死锁);
如下情况,处于阻塞状态的线程重新进入就绪状态:
sleep方法超过了时间;
调用的阻塞IO方法返回;
成功取得同步监视器;
等待某个通知,其他线程发出了通知;
处于挂起状态的线程 被 调用了resume;
死亡状态
如下情况,进入死亡状态:
run方法执行结束;
线程抛出一个Exception或Error;
直接调用stop方法(容易死锁);
判断某个线程是否死亡,使用isAlive;
处于 就绪&运行&阻塞 状态时,返回true;
处于 新建&死亡 状态时,返回false;
线程控制
join
让一个线程 等待 另一个线程完成;
在当前线程中 调用 其他线程的join,当前线程将一直被阻塞,直到被加入的线程执行完成;
sleep
在当前线程中 调用 sleep,当前线程将被一直阻塞,直到过了sleep时间;
yield
Thread的static方法,让当前正在执行的线程 暂停 但 不会阻塞(进入就绪状态);
当调用了Thread的yield方法后,只有 与当前线程同等优先级 或 大于当前线程优先级的线程 才有抢占CPU资源的机会;
线程的协调运行
Object的Wait()&Notify()&NotifyAll()
这3个方法 必须由 同步监视器 调用;
wait():
导致 当前线程等待,直到 其他线程调用该同步监视器的notify()/notifyAll() ;
notify():
唤醒 在此同步监视器上 等待的单个线程(如果有多个,随机唤醒一个);
notifyAll():
唤醒 在此同步监视器上 等待的所有线程;
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | public class WaitAndNotifyTest { public static void main(String[] args) { Account account = new Account(0); Thread t1 = new Thread( new Runnable() { @Override public void run() { Sender sender = new Sender(account); for ( int i = 1; i<= 100; i++){ sender.getAccount().save(i); } } }, "saver" ); Thread t2 = new Thread( new Runnable() { @Override public void run() { Getter getter = new Getter(account); for ( int i = 1; i<= 100; i++){ getter.getAccount(). get (i); } } }, "getter1" ); t1.start(); t2.start(); } public static class Sender{ Account account; Sender(Account account){ this .account = account; } public Account getAccount() { return account; } public void setAccount(Account account) { this .account = account; } } public static class Getter{ Account account; Getter(Account account){ this .account = account; } public Account getAccount() { return account; } public void setAccount(Account account) { this .account = account; } } public static class Account{ private Integer ye; private boolean isHave = false ; Account(Integer ye){ this .ye = ye; } public Integer getYe() { return ye; } public void setYe(Integer ye) { this .ye = ye; } public void setHave(boolean have) { isHave = have; } public boolean isHave() { return isHave; } public synchronized void save(Integer ye){ try { if (isHave){ this .wait(); } System. out .println(Thread.currentThread().getName() + " save " + ye); this .ye += ye; System. out .println(Thread.currentThread().getName() + " save end ye : " + ye); isHave = true ; this .notifyAll(); } catch (Exception e){ e.printStackTrace(); } } public synchronized void get (Integer ye){ try { if (!isHave){ this .wait(); } System. out .println(Thread.currentThread().getName() + " get " + ye); this .ye -= ye; System. out .println(Thread.currentThread().getName() + " get end ye : " + ye); isHave = false ; this .notifyAll(); } catch (Exception e){ e.printStackTrace(); } } } } |
使用条件变量控制协调
使用Lock保证同步,因为不存在隐式的 同步监视器对象,不能使用wait/notify/notifyAll;
Java提供了Condition来保持协调:
使得到Lock 但 无法继续执行的线程 释放Lock;
唤醒其他处于等待的线程;
Condition对象 被绑定到 Lock对象上;
获得特定Lock对象的Condition对象,使用lock对象的newCondition();
Lock替代了 synchronized的同步方法/同步代码块,Condition替代了 同步监视器;
Condition提供的方法:
await():
导致当前线程等待,直到 其他线程调用该Condition的singal()/singalAll();
singal():
唤醒在此Lock上等待的单个线程(随机唤醒其中一个等待的线程);
singalAll():
唤醒在此Lock上等待的所有线程;
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | public class LockConditionTest { public static void main(String[] args) { Account account = new Account(0); Thread t1 = new Thread( new Runnable() { @Override public void run() { Sender sender = new Sender(account); for ( int i = 1; i<= 100; i++){ sender.getAccount().save(i); } } }, "saver" ); Thread t2 = new Thread( new Runnable() { @Override public void run() { Getter getter = new Getter(account); for ( int i = 1; i<= 100; i++){ getter.getAccount(). get (i); } } }, "getter1" ); t1.start(); t2.start(); } public static class Sender{ Account account; Sender(Account account){ this .account = account; } public Account getAccount() { return account; } public void setAccount(Account account) { this .account = account; } } public static class Getter{ Account account; Getter(Account account){ this .account = account; } public Account getAccount() { return account; } public void setAccount(Account account) { this .account = account; } } public static class Account{ private Integer ye; private boolean isHave = false ; private final Lock lock = new ReentrantLock(); private final Condition condition = lock .newCondition(); Account(Integer ye){ this .ye = ye; } public Integer getYe() { return ye; } public void setYe(Integer ye) { this .ye = ye; } public void setHave(boolean have) { isHave = have; } public boolean isHave() { return isHave; } public void save(Integer ye){ lock . lock (); try { if (isHave){ condition.await(); } System. out .println(Thread.currentThread().getName() + " save " + ye); this .ye += ye; System. out .println(Thread.currentThread().getName() + " save end ye : " + ye); isHave = true ; condition.signalAll(); } catch (Exception e){ e.printStackTrace(); } finally { lock .unlock(); } } public void get (Integer ye){ lock . lock (); try { if (!isHave){ condition.await(); } System. out .println(Thread.currentThread().getName() + " get " + ye); this .ye -= ye; System. out .println(Thread.currentThread().getName() + " get end ye : " + ye); isHave = false ; condition.signalAll(); } catch (Exception e){ e.printStackTrace(); } finally { lock .unlock(); } } } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2019-01-26 Linux---目录结构