最新要闻
- 热门:512GB售价8999元:雷克沙发布新款CFexpress Type-B存储卡
- 今日热闻!459元 腾达发布首款面板AP:10秒下载一部电影
- 2023央视3·15晚会第一曝 “泰国香米”竟是香精勾兑!渉事公司食品许可证已失效
- 全球快消息!hdr和sdr区别_hdr
- 快消息!SteamDeck升级OLED屏无望:V社称难度比预想中更高
- 焦点播报:俄式风味!秋林格瓦斯:12瓶到手24元 0脂低糖
- 微星推出G2712电竞显示器:170Hz高刷、1ms响应
- 全球消息!“史诗级产品”!GPT-4来了:看图玩梗考律师 能力超90%人类
- 世界消息!偷工减料!南京蜜雪冰城频繁改标签过期继续用 被责令整改
- 网易云音乐会员不再支持车机版 车上听歌要加钱
- 天天滚动:U20国足队长出局后一夜没睡:裁判对中国队不公
- 焦点观察:中国土豪花109万元购买《CS:GO》AK47野荷皮肤 网友吐槽太丑
- 长安深蓝SL03行驶中自燃 车尾冒出明火和浓烟
- 世界看热讯:上海网红餐厅火烧云吃出异物:店家称没吃出问题就算了
- 【世界速看料】充电慢犯法!iPhone 15若限制充电速度或违反欧盟法律
- 当前观点:词典笔迎来第三代!阿尔法蛋AI词典笔T20图赏
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
Java并发小结02
主要参考自《实战Java高并发程序设计》。
线程与进程
进程是计算机系统进行资源分配和调度的基本单位,是线程的容器。
线程是处理器任务调度和执行的基本单位。
(资料图)
这里可以复习一下进程和线程的区别:
根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。
影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。
线程的生命周期
-新建NEW-就绪RUNNABLE-运行RUNNING-阻塞BLOCKED-死亡DEAD
线程的所有状态都在Thread中State枚举中定义:
cpublic enum State{ NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED;}
、、NEW状态表示刚刚创建线程还没开始执行。等到线程的start()方法调用时,才表示线程开始执行。当线程开始执行时处于RUNNABLE状态,标识线程所需的一切资源都已经准备好了。如果线程在执行过程中遇到了synchronized同步块,就会进入BLOCKED阻塞状态,知道获得请求的锁。WAITING和TIMED——WAITING都表示等待状态,区别是WAITING会进入一个无时间限制的等待,TIMED_WAITING会进行一个有限的等待。、、等待在等什么呢?一般来说WAITING的现场正是在等待一些特殊的时间。比如通过wait()方法等待的线程在等待notify()方法,而通过join()方法等待的线程则会等待目标线程的终止。一旦等到了期望的时间,线程就会继续执行,进入RUNNABLE状态。当前线程执行完毕后,则进入TERMINATED状态,表示结束。
线程的基本操作
新建线程
新建线程有三种方式:-new Thread-implements Runnable-implements Callable
new Thread
Thread t1 =new Thread(){@overridepublic void run(){...}};t1.start();
new一个Thread需要两个方法:run(),start()。
- start()方法用来创建一个线程并且让这个线程执行run()方法。
- run()方法是这个线程的任务,提供给使用者重写。
implements Runnable
源代码:
public interface Runnable { void run();}
运用示例:自定义类实现Runnable并重写run()方法,用Thread实现。
public class CreateThread implements Runnable{public static void main(String[] args){Thread t1=new Thread(new CreateThread()){t1.start();}@overridepublic void run(){...}}
上述代码实现了Runnable接口并将该实例传入线程Thread中,这样避免重写Thread.run()方法,单纯使用接口来定义线程Thread,也是最常用的做法。
- Thread有一个特殊的构造方法:
public Thread(Runnable target)
默认的Thread.run()方法就是直接调用内部的Runnable接口。因此使用Runnable接口告诉线程该做什么更为合理。
implements Callable
源代码:
public interface Callable { V call() throws Exception;}
可以发现Callable内部有一个call()方法并且带有返回值。运用示例:
public class CallableTest implements Callable{private String str;public CallableTest(String str){this.str=str;}@overridepublic String call() throws Exception{···return this.str;}}
自定义类实现Callable并重写call()方法。
那么怎么实现这个线程呢?Thread是没有直接实现Callable的构造函数的。
在设计模式中建立两者之间的关系经常使用适配器。什么是适配器呢?适配器就是接口转换器。把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
**找到Thread与Callable之间的适配类:FutureTask **
Thread有构造函数 public Thread(Runnable target)
Runnable的子类FutureTask可用于包装Callable或Runnable对象。
使用方式:重写call()方法,用FutureTask封装Callable类,用Thread去实现线程。
public class CallableTest implements Callable{ private String str; public a01CreateCallableThread(String str) { this.str = str; } @Override public String call() throws Exception { System.out.println("callable is called "); return this.str; } public static void main(String[] args) throws ExecutionException, InterruptedException { Callable c1 = new a01CreateCallableThread("xxx"); FutureTask task = new FutureTask(c1); long beginTime = System.currentTimeMillis(); //创建线程 new Thread(task).start(); //调用get()方法阻塞主线程 String str = task.get(); long endTime = System.currentTimeMillis(); System.out.println("hello :" + str); System.out.println("time :" + (endTime - beginTime) / 1000); }}
所以Callable与Runnable最大的区别就是Callable的执行方法call()有返回值,换个说法,Callable可以生成有返回值的线程。Future是一种异步任务监视器,以后的章节应该会说明,此处可忽略。
终止线程
一般来说,线程执行完毕就会结束,无需手动关闭。但是一些服务端的后台线程可能会常驻系统,它们通常不会正常终结。如何正常地关闭一个线程呢?Thread提供了一个stop()方法,但是已经被弃用了,因为stop()会强行把执行到一半的线程终止,可能会引起数据不一致的问题。
- 使用退出标志退出线程用一个boolean值来控制while循环是否退出
@Overridepublic void run(){while(!exit){//do something}}
中断线程
Thread.interrupt()
Thread提供interrupt()方法来中断线程(只是给一个中断的标记,并不会真正中断线程,真正中断是因为退出while循环)
提供isInterrupted()方法来判断是否被中断
提供interrupted()方法既可以判断是否中断又可以清除中断状态
示例:
public class a02InterruptThread { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread() { @Override public void run() { while (true) { System.out.println("~~~t1在执行~~~"); if (Thread.interrupted()) { System.out.println("Interrupted!"); break; } } } }; /** * t1 一直保持yield让出cpu */ t1.start(); /** * 主线程等待两秒 */ Thread.sleep(2000); /** * 中断t1 */ t1.interrupt(); }}
结果是t1运行两秒后会中断.
Thread.sleep(long millis)
Thread.sleep()方法会让当前线程休眠一段时间,之后继续执行,期间如果被中断会抛出InterruptedException中断异常.
等待和通知
JDK提供了两个非常重要的方法:Object.wait()和Object.notify(),这两个方法在Object类中.
当一个对象实例调用wait()方法后,当前线程就会在这个对象上等待.比如在线程A中,调用了obj.wait()方法,那么线程A就会停止执行转为等待状态.一直等待到其他线程调用该对象obj.notify()方法为止.
如果一个线程调用了obj.wait()方法,那么它会进入object对象的等待队列(可能有多个线程在等待).当obj.notify()方法被调用时,随机从等待队列中随机选择一个线程唤醒.
Object提供notifyAll()方法唤醒等待队列中的所有线程.
需要注意的一点:wait()和notify()方法都需要先获得目标对象的一个监视器,也就是目标对象需要有锁并且运行wait()或notify()方法的线程还需要获得这个锁.
代码示例:
public class a03WaitXNotify { final static Object object = new Object(); public static void main(String[] args) { Thread t1 = new Thread(() -> { synchronized (object) { System.out.println("t1 start"); try { System.out.println("t1 is waiting"); object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t1 is end"); }); Thread t2 = new Thread(() -> { synchronized (object) { System.out.println("t2 start"); System.out.println("object notify"); object.notify(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); /** * wait 和 notify 方法,都必须在synchronized代码块中执行,目的是为了获得监视器 * t1 获得监视器,执行object.wait进行等待,并释放监视器 * t2 获取监视器,执行object.notify释放t1,并且释放监视器 * t1 被唤醒,继续执行 */ t1.start(); t2.start(); }}
结果是:
t1与t2的执行流程如下:
挂起和继续执行
Thread类提供suspend()方法和resume()方法来将线程挂起和继续执行.
已经被废弃.原因是suspend()方法在导致线程暂停的同时并不会释放任何的锁资源.其他任何线程想要访问被它占用的锁都会被牵连.而且,如果suspend()方法意外的在suspend()方法前面执行就会导致死锁.线程即使suspend()了也在RUNNABLE状态
可以用wait()和notify()来替代,wait()会在等待的时期让出锁资源避免了资源浪费.
代码示例:
public class a03WaitXNotifyKillSuspend { /** * wait notify 替代 suspend 的线程挂起方案 */ public static Object u = new Object(); public static class ChangeObjectThread extends Thread { volatile boolean suspendme = false; /** * 让线程挂起的方法 */ public void suspendMe() { suspendme = true; } /** * 让线程继续执行的方法 */ public void resumeMe() { suspendme = false; synchronized (this) { notify(); } } @Override public void run() { /** * 看这里,之前是对while的中断标志进行改变来控制中断 */ while (true) { synchronized (this) { /** * 现在获得锁的情况下控制线程是否等待 * 判断自己是否被挂起(挂起标志),如果是则等待 * 否则正常执行 */ while (suspendme) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 让出cpu */ synchronized (u) { System.out.println(" in ChangeObjectThread"); } Thread.yield(); } } } } public static void main(String[] args) throws InterruptedException { ChangeObjectThread t1 = new ChangeObjectThread(); t1.start(); Thread.sleep(1000); System.out.println("-----------------------------"); t1.suspendMe(); System.out.println("suspend t1 30s"); Thread.sleep(30000); System.out.println("-----------------------------"); System.out.println("resume t1"); t1.resumeMe(); }}
结果是: t1 输出1s后被挂起30s,之后继续执行.如果在t1挂起期间此时有另外的线程是可以正常执行的,因为wait()会释放锁资源.
等待线程和谦让
Thread类提供join()来等待线程提供静态方法yeild()来礼让线程
join():
第一个join()会无线等待,一直阻塞当前线程,知道目标线程执行完毕.第二个join等待一段时间,即使目标线程没有执行完毕也会向下执行.(不等了)
public class Test { private static volatile long _longVal = 0; public static void main(String[] args) { Thread t1 = new Thread(new LoopVolatile1()); t1.start(); try {//让主线程等待t1执行完毕 t1.join(); } catch (Exception e) { e.printStackTrace(); } System.out.println("final _longVal is: " + _longVal); } private static class LoopVolatile1 implements Runnable { public void run() { long val = 0; while (val < 100000) { _longVal++; val++; } } }
结果是100000如果没有join(),大家可以试一下,结果是0,或者其他数字,因为主线程执行太快了t1都没执行完就结束了.
这里插一个t2线程,你决定结果是多少呢? 按理来说主线程和t2等待t1执行完,然后主线程等待t2执行完,结果应该是200000.但是结果几乎不可能为200000
public class Test { private static volatile long _longVal = 0; public static void main(String[] args) { Thread t1 = new Thread(new LoopVolatile1()); t1.start(); Thread t2 = new Thread(new LoopVolatile2()); t2.start(); try { t1.join(); t2.join(); } catch (Exception e) { e.printStackTrace(); } System.out.println("final _longVal is: " + _longVal); } private static class LoopVolatile1 implements Runnable { public void run() { long val = 0; while (val < 100000) { _longVal++; val++; } } } private static class LoopVolatile2 implements Runnable { public void run() { long val = 0; while (val < 100000) { _longVal++; val++; } } }}
这就涉及到了volatile对复合操作没有原子性,而i++是一个复合操作哦!
下次看volatile
yield():yield()会让出当前cpu,重新加入争夺cpu的队列.
关键词:
当前动态:Windows 下 JNA 调用动态链接库 dll
Java并发小结02
【新视野】区块链技术入门教程 - Decert
热门:512GB售价8999元:雷克沙发布新款CFexpress Type-B存储卡
今日热闻!459元 腾达发布首款面板AP:10秒下载一部电影
2023央视3·15晚会第一曝 “泰国香米”竟是香精勾兑!渉事公司食品许可证已失效
快播:第130篇:BOM(window对象)
全球快消息!hdr和sdr区别_hdr
快消息!SteamDeck升级OLED屏无望:V社称难度比预想中更高
焦点播报:俄式风味!秋林格瓦斯:12瓶到手24元 0脂低糖
微星推出G2712电竞显示器:170Hz高刷、1ms响应
全球消息!“史诗级产品”!GPT-4来了:看图玩梗考律师 能力超90%人类
世界消息!偷工减料!南京蜜雪冰城频繁改标签过期继续用 被责令整改
环球速递!火山引擎数智平台 VeDI 帮助智能投影仪更懂用户需求
天天观察:【学习日志】Java基本数据类型的自动装箱和拆箱
焦点滚动:智能制造 | AIRIOT智慧工厂管理解决方案
看热讯:iOS转场之present与dismiss的使用
网易云音乐会员不再支持车机版 车上听歌要加钱
天天滚动:U20国足队长出局后一夜没睡:裁判对中国队不公
焦点观察:中国土豪花109万元购买《CS:GO》AK47野荷皮肤 网友吐槽太丑
长安深蓝SL03行驶中自燃 车尾冒出明火和浓烟
世界看热讯:上海网红餐厅火烧云吃出异物:店家称没吃出问题就算了
当前速读:Linux LVM磁盘分区管理
环球今头条!记录--前端实现电子签名(web、移动端)通用
新动态:GPT-4 重磅发布,用户直呼:强得离谱
【聚看点】Python处理Unicode字符时出现中文乱码的情况
世界今亮点!go开发入门篇之go语言
【世界速看料】充电慢犯法!iPhone 15若限制充电速度或违反欧盟法律
当前观点:词典笔迎来第三代!阿尔法蛋AI词典笔T20图赏
每日播报!旧车置换宝马新车?4S店销售“张伟”骗了13位车主200余万元
【世界播资讯】国内喝星巴克的人越来越少了引热议:至少30元/杯、国人消费理智、竞争加剧
焦点简讯:电影《红海行动2》今年开拍:前作票房超36亿 网友“自来水”安利
【全球快播报】10999元起 LG gram Style轻薄本开售:轻至999g
天天新动态:HTML/XML字符转义对照表
环球新消息丨易基因:高通量测序后的下游实验验证方法——ChIP-seq篇|干货系列
焦点观察:爬虫-requests
记一次运气非常好的服务器渗透经历
【环球快播报】Chrome高级调试技巧
《黑暗荣耀2》演员被查有无校园暴力 空姐名场面是CG
【世界报资讯】《暗黑破坏神4》终极版宣传片发布:花100美元提前4天玩 还送坐骑等
当前最新:六分钟泡出武汉热干面 原汁味道!大汉口速食热干面大促:2.5元/袋
全球热议:借车给朋友车祸致人死亡!车主被判担责三成
实现内屏自动开合!魅族新折叠屏手机专利公布
全球简讯:外网信息搜集
每日热门:这啥?竟能让羊毛党无能狂怒!|无感验证还不快来体验
全球快讯:02.SQL
通过随机数Random 和 redis的incr每次增加一的原子性来动态绑定队列
uniapp,常用工具函数
天天讯息:2023年3月15日商丘嘉盛纸业A级箱板纸价格下调
每日信息:扫码点餐索要手机号违法吗?消保委暗访奶茶店和快餐店
全球热讯:山航就中国俄航等调侃信息发声明:不认同不符合客观事实的内容
东方甄选被曝养殖虾当野生虾卖 官方回应:被供应商骗了
【世界快播报】三星回应Galaxy S23 Ultra拍月亮“造假”:未进行任何图像叠加处理
世界聚焦:不给友商留机会 GPT-4大量技术细节不再公开:安全更重要
天天观焦点:CentOS 7 安装 YApi
易基因:染色质免疫共沉淀测序(ChIP-seq)的数据挖掘思路 |干货系列
fabric使用
当前简讯:企业微信对接openai实现chatgpt3.5聊天机器人
焦点快报!濒死恒星演化成超新星前一幕被韦伯捕捉:壮观至极!
全球热议:OpenAI还在烧钱 但开发者已经利用GPT挣钱了:还是国产的
FIFA官宣2026世界杯改制:48队分为12个组 赛事总场次增至104场
环球即时:合肥发布新能源汽车消费补贴政策:最高补贴5000元
环球动态:真不用羡慕油车了!特斯拉V4超级充电桩落地:最高功率350kW
全球快资讯:VMware安装虚拟机时提示错误"Failed to install the hcmon driver."解决办法
环球即时看!C# || 批量翻译工具 || 百度翻译api || 读取.cs文件内容 || 正则表达式筛选文件
这是一篇纯讲SQL语句优化的文章!!!| 博学谷狂野架构师
消息!前端架构工作
【全球速看料】Linux进程通信 | 管道与FIFO
全球微速讯:智动力:目前暂未涉及6G通信网络相关领域
焦点速讯:你支持吗?快递不告而放或最高可罚3万 直接放菜鸟也不接受?
【天天速看料】哪吒汽车跟进90天保价 哪吒S 1160增程小版限时17.98万元
林依晨和郑元畅在一起过吗?林依晨和郑元畅参加的综艺节目叫什么?
泰坦尼克号是真实的故事吗?泰坦尼克号的男女主角叫什么?
前锋燃气灶质量怎么样?燃气灶十大品牌排行榜
iis是什么软件?iis在哪里打开?
aspx文件是什么?aspx文件怎么打开?
Prime95烤机教程
观点:成人崩溃就在一瞬间 外卖小哥酒后误上高速 电量跑光痛哭不止
全球今头条!生产环境触目惊心!汕头知名橄榄菜企业被连夜查处:线上平台火速下架
播报:全周期订单数突破35万!魅族20系列无界超前订圆满结束
湖南邵阳疑似挖出龙化石?当地回应:或为天然石头
世界视点!Model Y行驶中刹车变硬 车主:售后说是常态化事情
GPT-4上线:史上最强大多模态语言模型,堪称最强人工智能,目前OpenAI付费升级GPT-4平台已崩溃
观点:报复性消费来了:我国网上零售额月均破万亿元
16岁女孩将挑战珠峰 父亲众筹50万 回应来了:女儿想法
奔驰EQC刚买半年驱动电机就被烧毁 车主质疑4S店故意欺诈
环球新动态:电机品牌排行榜_电机品牌
环球速递!文盘Rust -- 安全连接 TiDB/Mysql
自从用了 EasyExcel,导入导出 Excel 更简单了!
浅谈var,let,const
今日最新!Maven学习笔记3:在idea中使用Maven
全球播报:玩家最喜欢的复古游戏TOP5:《俄罗斯方块》排第二
环球快资讯:程序员也危险了!GPT-4十秒即可生成一个网站
焦点消息!ChatGPT升级为GPT-4 会看图懂幽默 细思极恐
充电慢、续航差、反馈无门!bZ3X首批车主公开致信广汽丰田董事长
不接董事长电话1次罚1万元 公司回应:合不合法你说了不算
项目构建node-sass源码报错 SyntaxError:Unexpectedtoken"?"
前端设计模式——命令模式
【热闻】保时捷去年净赚499亿元:国人给力 中国连续八年为最大市场
打工几年就能买北京四合院?新剧《心想事成》开播引热议