范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

从1990年的论文来详细聊聊AQS的前世今生

  今天的主题是AbstractQueuedSynchronizer,即AQS。作为java.util.concurrent的基础,AQS在工作中的重要性是毋庸置疑的。通常在面试中也会有两道"必考"题等着你:原理相关:AQS是什么?它是怎样实现的?设计相关:如何使用AQS实现Mutex?
  原理相关的问题几乎会出现在每场Java面试中,是面试中的"明枪",是必须要准备的内容;而设计相关的问题更多的是对技术深度的考察,算是"暗箭",要尤为谨慎的去应对。
  为了全面地理解AQS的设计,今天我们会从1990年T.E.Anderson引入排队的思想萌芽开始,到Mellor-Crummey和Scott提出的MCS锁,以及Craig,Landin和Hagersten设计的CLH锁。
  AQS的内容整体规划了4个部分:
  今天我们一起学习前两个部分,了解AQS的前世。
  Tips:本文基于Java 11完成,与Java 8存在部分差异,请注意区分源码之间的差异。AQS是什么?
  通常我们按照类名将AbstractQueuedSynchronizer翻译为抽象队列同步器。单从类名来看,我们就已经可以得到3个重要信息:Abstract:抽象类,通常无法直接使用;Queued:队列,借助队列实现功能;Synchronizer:同步器,用于控制并发。
  源码中的注释也对AQS做了全面的概括:
  Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues.
  提供了依赖于FIFO等待队列用于实现阻塞锁和同步器(信号量,事件等)的框架。这段描述恰好印证了我们通过类名得到的信息,我们来看Java中有哪些AQS的实现:
  可以看到,JUC中有大量的同步工具内部都是通过继承AQS来实现的,而这也正是Doug Lea对AQS的期望:成为大部分同步工具的基础组件。
  Tips:至少在Java 8中,FutureTask已经不再依赖AQS实现了(未考证具体版本)。
  接着我们来看注释中提到的"rely on first-in-first-out (FIFO) wait queues",这句话指出AQS依赖了FIFO的等待队列。那么这个队列是什么?我们可以在注释中找到答案:
  The wait queue is a variant of a "CLH" (Craig, Landin, and Hagersten) lock queue. CLH locks are normally used for spinlocks.
  AQS中使用的等待队列时CLH队列的变种。那么CLH队列是什么呢?AQS做了哪些改变呢?AQS的前世
  AQS明确揭示了它使用CLH队列的变种,因此我从CLH队列的相关论文入手:Craig于1993年发表的《Building FIFO and priority-queueing spin locks from atomic swap》Landin和Hagersten于1994年发表的《Efficient Software Synchronization on Large Cache Coherent Multiprocessors》
  这两篇文章都引用了T.E.Anderson于1990年发表的的《The Performance of Spin Lock Alternatives for Shared-Memory Multiprocessors》,因此我们以这篇文章中提出的基于数组的自旋锁设计作为切入点。
  Tips:《Efficient Software Synchronization on Large Cache Coherent Multiprocessors》的作者有3个人~~Landin和Hagersten的《Efficient Software Synchronization on Large Cache Coherent Multiprocessors》中引用了Craig的《Building FIFO and priority-queueing spin locks from atomic swap》,Craig率先提出了CLH锁的结构,不知道为什么学术界以他们3人进行命名;由于论文是很多年前收集的,现在去查找原始网站较为困难,只能提供下载链接了,对不起各位祖师爷~~ T.E.Anderson The Performance of Spin Lock Alternatives for Shared-Memory Multiprocessors 1990 Mellor Crummey,Scott Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors 1991 Craig Building FIFO and priority-queueing spin locks from atomic swap 1993 Landin, Hagersten Efficient Software Synchronization on Large Cache Coherent Multiprocessors 1994 Doug Lea The java.util.concurrent Synchronizer Framework 2004《多处理器编程的艺术》中第7章详细讨论了队列锁的设计,包括基于数组的设计,MCS锁,CLH锁。基于数组的自旋锁
  1990年T.E.Anderson发表了《The Performance of Spin Lock Alternatives for Shared-Memory Multiprocessors》,文章讨论了基于CPU原子指令自旋锁的性能瓶颈,并提出了基于数组的自旋锁设计。基于原子指令的自旋锁
  第一种设计(SPIN ON TEST-AND-SET),即TASLock,使用CPU提供的原子指令test-and-set尝试更新锁标识:
  初始化锁标识为CLEAR,获取锁时尝试更新锁标识为BUSY,更新成功则获取到锁,释放时将锁标识更新为CLEAR。
  设计非常简单,竞争并不激烈的场景下性能也是完全没问题,但是一旦CPU的核心数增多,问题就出现了:持有者在释放锁时要和其它正在自旋的竞争者争夺锁标识内存的独占访问权限,因为test-and-set是原子写操作;在使用总线的体系结构中,无论test-and-set指令是否成功,它都会消耗一次总线事务,会使总线变得拥堵。
  因此提出了第二种设计(SPIN ON READ),即TTASLock,加入test指令,避免频繁的:
  该设计中,在执行test-and-set指令前,先进行锁标识状态的判断,处于BUSY状态,直接进入自旋逻辑(或运算的短路特性),跳过test-and-set指令的执行。
  额外一次读取操作,避免了频繁的test-and-set指令造成的内存争抢,也减少了总线事务,竞争者只需要自旋在自己的缓存上即可,只有锁标识发生改变时,才会执行test-and-set指令。
  这种设计依旧有些性能问题无法解决:如果频繁锁标识频繁的发生改变,CPU的缓存会频繁的失效,重新读取;持有者释放锁时,会导致所有CPU的缓存失效,必须重新在内存或总线中竞争。
  T.E.Anderson对两种设计进行了测试,计算了在不同数量的CPU上执行了100万次操作的耗时,执行等待锁,执行临界区,释放锁和延迟一段时间。
  可以看到SPIN ON READ的设计随着CPU数量的增多性能确实得到了改善,但距离理想的性能曲线仍有着不小的差距。
  除了这两种设计外,T.E.Anderson还考虑了在自旋逻辑中引入延迟来减少冲突:
  此时需要考虑设置合理的延迟时间,选择合适的退避(backoff)算法来减少竞争。
  Tips:Java版TASLock和TTASLock,供大家参考。基于数组的自旋锁
  前面的设计中,自旋锁的性能问题是由多个CPU同时争抢内存访问权限产生的,那么让它们按顺序排队是不是就解决了这个问题?T.E.Anderson引入了队列的设计:
  初始化创建长度为CPU数量P的数组flags[P]flags[0]标识为HAS_LOCK(拥有锁),其余标记为MUST_WAIT(等待锁)初始化queueLast为0,标识当前队列位置
  加锁CPU通过ReadAndIncrement指令读取queueLast后保存为自己的myPlace ReadAndIncrement指令,先读取,后自增CPU判断自己的flags[myPlace mod P]上的标记来决定持有锁或进入自旋 取模操作让数组变成了头尾相连的"环状"数组
  解锁将当前CPU在队列中的位置flags[myPlace]更新为MUST_WAIT将flags[(myPlace + 1) mod P]更新为HAS_LOCK,标识下一个CPU获取锁
  每个CPU只访问自己的锁标识(myPlace),避免了争抢内存访问的权限,另外锁会直接释放给队列中的下一个CPU,避免了通过竞争获取,减少了从释放锁到获取锁的时间。
  当然缺点也很明显,仅从伪代码的行数上也能看出来,基于队列的自旋锁设计更复杂,当竞争并不激烈时,它的性能会更差。T.E.Anderson也给出了他的测试结果:
  很明显,在竞争激烈的场景中,引入队列后的自旋锁性能更加优秀,并没有过多的额外开销。
  Tips:T.E.Anderson的论文就介绍到这里,除了对自旋锁的讨论,文章中还讨论了在自旋锁引入退避算法和静态延迟(static delays)的优劣,就留给大家自行阅读了;Java版TEALock,供大家参考(名字是我自己起的~)。MCS锁的设计
  基于数组的自旋锁是排队思想的实现,T.E.Anderson的论文发表后,又涌现出了许多使用排队思想锁,例如:Mellor-Crummey和Scott于1991年在论文《Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors》中提出的MCS锁,也是基于排队思想实现,只不过在数据结构上选择了单向链表。
  描述MCS锁的初始化与加解锁的原理,我使用经过"本地化"的Java实现版本的MCS锁:MCS锁的初始化public class MCSLock {    AtomicReference lock;      ThreadLocal myNode;      public MCSLock() {     this.lock = new AtomicReference<>(null);     this.myNode = ThreadLocal.withInitial(QNode::new);   }      private static class QNode {     private boolean locked;     private QNode next;   } } 复制代码声明单向链表的节点QNode,locked表示锁是否被前驱节点获取;创建QNode节点lock,表示当前锁的位置,实际上也是链表的尾节点。MCS锁的加锁public void lock() {   QNode I = this.myNode.get();   QNode predecessor = this.lock.getAndSet(I);   if (predecessor != null) {     I.locked = true;     predecessor.next = I;     while (I.locked) {       System.out.println("自旋,可以加入退避算法");     }   } } 复制代码为每个线程初始化QNode,命名为I;通过原子指令获取I的前驱节点lock命名为predecessor,并将I设置为lock(取出当前lock,并设置新的lock); 当predecessor == null时,表示队列为空,可以直接返回,代表获取到锁; 当predecessor != null时,表示前驱节点已经获取到锁; 更新locked,表示锁已经被前驱节点获取; 更新predecessor的后继节点为I,否则predecessor无法唤醒I; I进入自旋逻辑。MCS锁的解锁public void unlock() {   QNode I = this.I.get();   if (I.next == null) {     if (lock.compareAndSet(I, null)) {       return;     }          while (I.next == null) {       System.out.println("自旋");     }   }      I.next.locked = false;   I.next = null; } 复制代码获取当前线程的QNode命名为I;如果I.next == null,队列中无其它节点,即不存在锁竞争的场景; 尝试通过CAS更新lock为null,保证下次加锁时predecessor == null,成功则直接返回; 如果失败,表示此时有线程开始竞争锁,此时进入自旋,保证竞争者成功执行predecessor.next = I;如果I.next != null,队列中有其他节点,锁存在竞争; 更新后继节点的locked标识,使其跳出自旋; 更新自己的后继节点指针,断开联系。
  MCS锁的逻辑并不复杂,不过有些细节设计的非常巧妙,提个问题供大家思考下:加锁过程中I.locked = true和predecessor.next = I的顺序可以调整吗?
  MCS锁的整体设计思路到这里就结束了,Mellor-Crummey和Scott给出了MCS锁的4个优点:FIFO保证了公平性,避免了锁饥饿;自旋标识是线程自身的变量,避免了共享内存的访问冲突;每个锁的创建只需要极短的时间(requires a small constant amount of space per lock);无论是否采用一致性缓存架构, 每次获取锁只需要O(1) O(1)O(1) 级别的通信开销。
  除此之外,相较于T.E.Anderson的设计,MCS锁在内存空间上是按需分配,并不需要初始化固定长度数组,避免了内存浪费。
  Tips:本文只简单的介绍MCS锁的原理,想要深入学习的可以阅读以下内容: 《Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors》 《多处理器编程的艺术》第7章Java版MCSLock,供大家参考,代码有详细的注释。CLH锁的设计
  1993年Craig发表了《Building FIFO and priority-queueing spin locks from atomic swap》,文章中描述了另一种基于排队思想的队列锁,即CLH 锁(我觉得称为Craig Lock更合适)的雏形,它和MCS锁很相似,但有一些差异:CLH旋转在队列前驱节点的锁标识上;CLH锁使用了一种"隐式"的链表结果。
  我们带着这两个差异来看CLH的锁的设计,原文使用Pascal风格的伪代码,这里我们使用《多处理器编程的艺术》中提供的Java版本,与论文中的差异较大,重点理解实现思路即可。CLH锁的初始化public class CLHLock {      AtomicReference tail;      ThreadLocal myPred;      ThreadLocal myNode;      public CLHLock() {     this.tail = new AtomicReference<>(new Node());     this.myNode = ThreadLocal.withInitial(Node::new);     this.myPred = new ThreadLocal<>();   }      private static class Node {     private volatile boolean locked = false;   } } 复制代码
  Craig的设计中,请求锁的队列节点有两种状态,在实现中可以使用布尔变量代替:PENDING,表示获取到锁或者等待获取锁,可以使用true;GRANTED,表示释放锁,可以使用false。
  另外CLHLock的初始化中,this.tail = new AtomicReference<>(new QNode())添加了默认节点,该节点的locked默认为false,这是借鉴了链表处理时常用到技巧虚拟头节点。CLH锁的加锁public void lock() {   Node myNode = this.myNode.get();   myNode.locked = true;   Node pred = this.tail.getAndSet(myNode);   this.myPred.set(pred);   while(myPred.locked) {     System.out.println("自旋,可以加入退避算法");   } } 复制代码
  实现中巧妙的使用了两个ThreadLocal变量来构建出了逻辑上的链表,和传统意义的单向链表不同,CLH的链表从尾节点开始指向头部。
  另外,CLH锁中的节点只关心自身前驱节点的状态,当前驱节点释放锁的那一刻,节点就知道轮到自己获取锁了。CLH锁的解锁public void unlock() {   Node myNode = this.myNode.get();   myNode.locked = false;   this.myNode.set(this.myPred.get()); } 复制代码
  解锁的逻辑也非常简单,只需要更新自身的锁标识即可。但是你可能会疑问this.myNode.set(this.myPred.get())是用来干嘛的?删除会产生什么影响吗?
  Tips:Java版CLHLock,供大家参考,代码有详细的注释。单线程场景
  在单线程场景中,完成CLH锁的初始化后,锁的内部结构是如下:
  Tips:@后表示Node节点的地址。
  第一次加锁后状态如下:
  这时前驱节点的锁标记为false,表示当前节点可以直接获取锁。
  第一次解锁后状态如下:
  到目前为止一切都很正常,但是当我们再次加锁时会发现,好像没办法加锁了,我们来逐行代码分析锁的状态。当获取myNode后并更新锁标识,即执行如下代码后:Node myNode = this.myNode.get(); myNode.locked = true; 复制代码
  当获取并更新tail和myPred后,即执行如下代码后:Node pred = this.tail.getAndSet(myNode); this.myPred.set(pred); 复制代码
  这时候问题出现了,myNode == myPred,导致永远无法获取锁。this.myNode.set(this.myPred.get())相当于在链表中移除当前节点,使获取锁的节点的直接前驱节点永远是初始化时锁标识为false的默认节点。多线程场景
  再来考虑多线程的场景,假设有线程t1和线程t2争抢锁,此时t1率先获取到锁:
  线程t1释放后再次立即获取是有可能出现的,最典型的情况是如果为自旋逻辑添加了退避算法,当线程t2多次自旋后再次进入自旋逻辑,此时线程t1释放锁后立即尝试获取锁,先更新线程t1的锁标记为true,接着从tail节点中获取前驱节点线程t2,然后再更新tail节点,此时线程t1在线程t2的锁标记上自旋,线程t2在线程t1的锁标记上自旋,凉凉~~
  留个思考题,为什么this.myNode.set(this.myPred.get())可以避免这种情况?CLH锁和MCS锁的对比
  首先是代码实现上,CLH锁的实现非常简单,除了自旋的部分其余全是平铺直叙,反观MCS锁,分支,嵌套,从实现难度上来看CLH锁更胜一筹(难点在于逆向思维,让当前节点自旋在直接前驱节点的锁标识上)。另外,CLH锁只在加锁时使用了一次原子指令,而MCS锁的加解锁中都需要使用原子指令,性能上也略胜一筹。
  那么CLH锁是全面超越了MCS锁吗?不是的,在NUMA架构下,CLH锁的自旋性能非常差。先来看NUMA架构的示意图:
  NUMA架构中,每个CPU有自己缓存,访问不同CPU缓存的成本较高,在需要频繁进入自旋的场景中CLH锁自旋的性能较差,而在需要频繁解锁更新其他CPU锁标识的场景中MCS锁的性能较差。结语
  到目前为止,我们一起学习了3种基于排队思想的自旋锁设计,作为AQS的"前世",理解它们的设计能够帮助我们理解AQS的原理。当然并非只有这3种基于排队思想的自旋锁,还有如RHLock,HCLHLock等,感兴趣的可以自行探索,这里提供论文链接:《RH Lock:A Scalable Hierarchical Spin Lock》《A Hierarchical CLH Queue Lock》
  好了,今天就到这里了,Bye~~
  作者:王有志
  链接:https://juejin.cn/post/7210043623759577125
  来源:稀土掘金
  著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

一花一世界,明媚春天,杜鹃花开满枝头,色彩艳丽,繁花似锦明媚的春天,暖暖的春风,花儿朵朵开,百花齐放竟芳香!因为疫情无法外出游玩,恐怕要让我们辜负了这大好春色!不过,可以在家云赏花!今天给大家分享几张杜鹃花美图!牡丹真国色,杜鹃花开也灿C语言基础篇选择顺序循环结构今日头条西瓜视频抖音短视频同名正点原子原子哥感谢各位的关注和支持,你们的支持是原子哥无限前进的动力。C语言基础篇选择顺序循环结构前言社会上习惯于把科学和技术连在一起,统称为科学技术共赴一场宋风雅集,2022清明奇妙游描绘山川画卷清明,在漫长历史长河演化至今,集合了清明寒食上巳三个节日的风俗和情感,这是一个祭祖追思的日子,也是一个踏青郊游的节日。如何体现清明节的人文和自然内涵?4月4日1830,由河南广播电2022春夏穿搭法则,照着穿作为一个时尚类的公众号,我们经常会跟大家分享一些时尚博主和主编的穿搭。不过其实在人才辈出的时尚界,有这个职业的存在,对于时尚潮流的演变,也有着不可忽视的作用。我说的,就是在各种大片半身裙不能随便搭配!这3个要点多套穿搭,全是借鉴干货这个春天,自带优雅感充满女人味的半身裙彻底火起来了,打开女人的衣橱,会发现,少则三四条半身裙,多则七八条半身裙。但需要大家注意的是,半身裙穿好的关键在于搭配,不会搭配,再多的半身裙女生必看的35个建议,提升你的格局给大家分享一段话世上的确有很多事,就算靠努力也是没有办法改变的,也正因为如此,在必须努力的时候,才更不能犹豫不前。怎么才能蜕变成更好的自己?来看看今天的35点提升格局的建议吧外貌篇巴丹吉林,凭什么被中国国家地理评为最美沙漠?在大众的刻板印象中沙漠应该是干涸贫瘠荒凉和单调的它不像森林草原雪地这些地貌每走一段路,眼前的景色就会变化而当你坐上越野车驶进巴丹吉林沙漠会惊叹于它诠释了一个沙漠新概念这里有着神奇的三人篮球国家队大集训名单公布4月8日在四川金强篮球训练基地开始今天(4月2日),中国篮协公布,为了备战杭州亚运会三人篮球亚洲杯世界杯U23世界杯等国际赛事,4月8日至5月17日将在四川金强篮球训练基地组织三人篮球国家男女队开展大集训和运动员选Selina小7岁男友正脸曝光,长相引争议,网友贼眉鼠眼配不上3月是一个春暖花开的季节,已经有很多明星传出绯闻。其中就有SHE成员Selina(任家萱),当天被曝出恋爱情后便大方的承认了。但是男方的身份一直没有公开,在3月30晚有八卦媒体拍到超大通量,6级精滤,云米泉先AI净水器SuperS1200G,引领芯实力作为一名90后,买房买车,结婚生子,在青岛这个新一线城市逐步安营扎寨,站稳脚跟。随着收入的逐步增加,也开始追求生活品质的提高。我遗传了父亲的基因,喜欢喝茶,所谓好水配好茶,才能萃出巨屏浪潮来袭!华为Mate50X或配备7。2英寸大屏,不止6000mAh电池这两天关于vivoXNote大屏商务旗舰的消息,吸引了很多用户关注,不少网友对该机的期待值也是很高的,也许是vivoXNote的出现,让不少厂商也感受到了市场,近日网上便曝光了一款
荣耀Note20Pro新机的曝光,前辈价崩残忍让路惊喜不断这样一款电竞产品,对于喜欢手游软件的用户来说,是一个不错的体验。荣耀Note20Pro基本算是确定了,有7英寸大屏1TB高存储,优势很明显了。新机还在孵化,荣耀的一些旧旗舰机型,开湖南亿万富豪易大盛收购多家国企,建长沙地标建筑,身价125亿1961年,易大盛出生于湖南省岳阳市岳阳县。29岁那年,他在岳阳开了一家小型汽车修理厂邦田汽修厂。在此之前,他的具体经历,无人知晓。这是易大盛发家的开始。当时,私人很少有汽车,汽修风景万里,皆不如你1。别人再风光,你也指望不上,眼前再不堪,生活也要继续,没人扶的时候,自己要站稳,没人帮你的时候,自己要努力,不要眼眶一热就觉得人间不值得,要相信你不可能什么都有,也不可能什么都没逼你买高配?苹果限制iPad10速度,iPhone15也要等级森严经过漫长的拉锯战,苹果终于承认会遵守欧盟的规定,未来产品都会改用TypeC接口,iPad系列平板已经完成改造。最新有网友发现,苹果似乎对不同定位产品作出硬性规定,廉价版设备不支持更打脸库里!麦迪不管怎么排,杜兰特的历史地位都应该要高于库里近期,著名篮球评论员麦迪在出席某篮球活动时直言论历史地位排名,杜兰特肯定是要高于库里,这点毫无争议!随后麦迪对自己发表的这个观点进行了详细的解释!1。杜兰特带领库里拿到了2个总冠军构建国内大循环为主体,国内国际双循环相互促进的新发展格局意义2021年国家公务员考试面试真题(3月17日部委党群及参公单位发改委)请你谈谈构建国内大循环为主体,国内国际双循环相互促进的新发展格局的意义?理论版本1。构建新发展格局有利于更好适2023年养老金上调,低于3100元多涨,高于6000元不再涨,可行吗?目前对于很多已经退休的人来说,养老金是他们唯一的收入来源,而这也就导致不少人对于养老金的变动格外关注。另外一方面则是由于养老金政策自发行以来,就一直随着我国经济水平的上涨而上涨。尤上山的路途越艰难,山顶的风景就越美,愿我们都能做自己的勇者勇于尝试,做自己的勇者机器人213陈基鹏什么是勇者,怎样才能算的上勇者,因为是勇者才敢去尝试吗,不,是因为敢于去尝试才是勇者。01勇于尝试,克服自卑。达芬奇曾说你只要尝试过飞,日后金秋泸沽湖三漫步走婚桥徜徉情人滩乘坐猪槽船环游泸沽湖一乘猪槽船环游泸沽湖大约中午11时,乘车来到洛洼码头。穿上桔红色的救生背心后,10人一组地分别登上了狭长形的木制小船因小船像农家喂养猪食的木槽,故称之为猪槽船。船上的人两两相坐,船2021年山东省医保支付品种扩大到3757个视频加载中10月27日山东省政府新闻办召开发布会,山东医药服务管理处处长一级调研员张庆国介绍,2020年,我省开展中药配方颗粒研究试点工作,分批将符合条件的我省试点企业生产的121发布了!国内新开超400条航线!1折机票来了!过冬游起飞?从10月30日至明年3月25日,中国民航将执行新的冬春航季航班计划,新航季国内新开航线超400条,主要涉及包头揭阳阿克苏德宏鄂尔多斯等机场与大连杭州昆明深圳重庆等机场间的航线。新航背水一战!曼联末轮须赢2球以上小组第二踢附加赛或遭遇三豪强10月28日凌晨,欧联杯小组赛拉开战幕,英超红魔曼联主场30轻取蒂拉斯波尔警长,达洛特拉什福德双双头球建功,C罗解禁归来首发出战两连击破门,帮助曼联彻底锁定胜局。不过这样一场胜利,巴拉格巴黎续约梅西有优势,哈维已和他谈过但巴萨没有实际行动直播吧10月28日讯梅西传记作家知名记者吉列姆巴拉格日前作客塞尔电台,并谈到了梅西的未来。巴拉格说道巴萨让后梅西时代来得太快,12月主席大选之前,梅西还告诉他的孩子,自己会留在巴塞罗晋唐嫣结婚4周年!不秀恩爱分隔两地,男方与张慧雯压腿太亲密罗晋唐嫣结婚4周年!不秀恩爱分隔两地罗晋和唐嫣这对明星夫妻一直很受大家的喜爱,两人可以说是郎才女貌天造地设的一对。自从两人在18年结婚到现在已经4年的时间,虽然网上也时不时的会传出中国只有15座新一线城市,成都高居第1,天津第9,大连没上榜我国境内拥有大大小小的城市数百个,有很多特色城市,像大家都知道的新一线城市就有15座,例如成都重庆郑州南京佛山合肥以及青岛等,这些地方都有不同的特点!但是大家肯定会发现一些端倪,就新闻观察前三季度中国就业形势总体稳定央视网消息日前,人力资源社会保障部发布三季度就业数据,19月城镇新增就业1001万人,三季度全国城镇调查失业率均值为5。4,比二季度下降0。4个百分点,就业形势总体稳定。在多重超预恒大危机及其引发的烂尾楼事件焉知非福要说中国的民营经济,就离不开温州的民营企业同样,说中国楼市,就不得不提到温州的大妈炒房团,一个单元一栋楼的组团买卖,也就只有山西煤老板可能望其项背了。温州人,在中国的改革开放进程中安徽这个民营经济强县,即将迈入高铁时代近日,有网友在人民网留言,建议天长市修建高铁。中共滁州市委办公室回复称,宁淮铁路安徽段初步设计已获批,先行工程已经开工,按照线路规划,宁淮铁路将在天长市设立车站。天长为安徽省县级市卤味第一股煌上煌三季度净利下滑超八成卤味市场竞争加剧封面新闻记者马梦飞10月28日早盘,煌上煌低开低走,截至午间收盘跌3。12,股价报9。95元,总市值50。97亿元。消息面上,昨日晚间,煌上煌披露三季报显示,公司第三季度净利润下滑日媒述评一带一路将助推人民币国际化日本经济新闻网站10月26日发表英国伊诺多经济公司首席经济学家戴安娜乔伊利瓦与该公司银行与金融市场分析师丁尼麦克马洪合写的文章,题为一带一路下一个篇章事关人民币。全文摘编如下虽然基国务院发文推动取消皮卡车进城限制,全面解禁指日可待?10月26日,国务院办公厅印发的第十次全国深化放管服改革电视电话会议重点任务分工方案(以下简称方案)中,再次提及皮卡。方案的第十四条明确,再推出一批便民服务措施,解决好与人民群众日iPad10发售就破发!此前黄牛曾亏本卖iPhone14苹果,不香了吗?上周,苹果发布了两款全新iPad,分别是第十代iPad以及M2款iPadPro。10月26日,这两款iPad正式发售。让人意想不到的是,iPad10发售当天即破发,第三方售价均低于