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

JUC(7)JMMampampampVolatile死磕内存模型

  前言
  1、你知道什么是 Java 内存模型 JMM 吗
  2、JMM 与 Volatile 它们两个之间的关系?
  3、JMM 有哪些特性 or 它的三大特性是什么?
  4、为什么要有 JMM,它为什么出现?作用和功能是什么?
  5、happens-before 先行发生原则你有了解过吗?一、JMM 入门1.1 概述
  硬件体系中存在多级的缓存,越往寄存器,则运算速度越快。
  CPU 的运行并不是直接操作内存而是先把内存里边的数据读到缓存,而内存的读和写操作就会造成不一致的问题。
  因为每个人用的操作系统不同,JVM 规范中试图定义一种 Java 内存模型(JMM)来屏蔽各种硬件和操作系统的内存访问差异。以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。所以,我们需要知道 JMM 。
  处理器出来的数据放入高速缓存中。我们可以在主内存和高速缓存中制定一个 缓存一致性协议。1.2 定义作用
  JMM(Java 内存模型 Java Memory Model)本身是一种抽象的概念,并不真实存在。它仅仅描述的是一组约定或规范,通过这组规范定义了程序中(尤其是多线程)各个变量的读写访问方式并决定一个线程对共享变量的写入何时对另外一个线程可见。
  关键技术点都是围绕多线程的原子性、可见性和有序性展开的 。
  能干么呢?
  1、通过 JMM 来实现线程和主内存之间的抽象关系
  2、屏蔽各个硬件平台和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的 内存访问效果。1.3 多线程对变量的读写过程主内存:线程的共享数据区域,主要存储的是 Java 实例对象,所有线程创建的实例对象都存放在主内存中工作内存:每个线程对应一个私有工作内存,主要存储当前方法的所有本地变量信息(共享数据的副本),也可以理解为本地内存
  JMM定义了线程和主内存之间的抽象关系
  ① 线程之间的共享变量存储在主内存中(从硬件角度来说就是内存条)
  ② 每个线程都有一个私有的本地工作内存,本地工作内存中存储了该线程用来读/写共享变量的副本(从硬件角度来说就是CPU的缓存,比如寄存器、L1、L2、L3缓存等)
  ③ 线程对共享变量所有的操作都必须先在线程自己的工作内存中进行后写回主内存,不能直接从主内存中读写(不能越级)
  ④ 不同线程之间也无法直接访问其他线程的工作内存的变量,线程间变量值的传递需要通过主内存来进行(同级不能相互访问)
  总线窥探:
  总线窥探是缓存中的一致性控制器监视或窥探总线事务的一种方案,其目标是在分布式共享内存系统中维护缓存一致性。当主内存的数据被修改后,需要将所有有该数据副本的工作内存的数据变更,这个数据变更通知可以通过总线窥探来完成,所有的窥探者都在监视总线上的每一个事务,如果一个修改共享数据的事务出现在总线上,所有的窥探者都会检查自己的副本是否有相同数据副本,若有则修改。1.4 八种内存交互
  read:作用于主内存,将变量的值从主内存传输到工作内存,主内存到工作内存;load:作用于工作内存,将 read 从主内存传输的变量值放入工作内存变量副本中,即数据加载use:作用于工作内存,将工作内存变量副本的值传递给执行引擎,每当 JVM 遇到需要该变量的字节码指令时会执行该操作。assign:作用于工作内存,将从执行引擎接收到的值赋值给工作内存变量,每当 JVM 遇到一个给变量赋值字节码指令时会执行该操作;store:作用域工作内存,将赋值完毕的工作变量的值写回给主内存;write:作用于主内存,将 store 传输过来的变量值赋值给主内存的变量;
  由于上述6条不能保证多条指令组合的原子性,没有大面积加锁lock:作用于主内存:将一个变量标记为一个线程独占的状态,只是写时候加锁,就只是锁了写变量的过程。unlock:作用于主内存,把一个处于锁定状态的变量释放,然后才能被其他线程占用。二、JMM 三大特性
  并发编程Bug 的源头:可见性、原子性和有序性问题。2.1 可见性2.1.1 案例
  修改变量的值。public class Demo1 {     private  boolean flag =true;     private int count = 0;      public void update(){         flag =false;         System.out.println(Thread.currentThread().getName()+"修改flag");     }     public void load()   {         while (flag){             count++;         }         System.out.println("结束线程,count = "+count);     }      public static void main(String[] args) throws InterruptedException {         Demo1 demo1 = new Demo1();         new Thread(()->{              demo1.load();         },"线程A").start();         // 等待三秒,看另外一个线程修改后,能否进入循环         Thread.sleep(3000);         new Thread(()->{             demo1.update();         },"线程B").start();     } } 复制代码
  控制台输出,线程B修改后,线程 A 无法终止,即无法读取到变量 flag 被其他线程修改了。2.1.2 可见性
  当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道该变更。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方法来实现可见性的。
  JMM 规定了所有的变量都存储在主内存中。
  每个线程都从主内存中读取共享变量的副本,然后修改后提交给主内存,确实像 git。
  系统主内存共享变量数据修改被写入的时机是不确定的,多线程并发下很可能出现 "脏读",所以每个线程都有自己的工作内存,线程自己的工作内存中保存了该线程使用到的变量的主内存副本拷贝。线程间变量值的传递均需要通过主内存来完成。2.1.3 如何保证可见性通过 volatile 关键字保证可见性java 中被 volatile 修饰的变量,在转变汇编指令后会添加一个 lock 前缀,lock 前缀的指令在多核处理器下做两件事:1、将当前处理器缓存行的数据写回系统内存 2、写回内存后,其他cpu缓存了该内存地址的数据无效通过内存屏障保证可见性通过 synchronized 关键字保证可见性加锁线程会获得锁,清空工作内存,从主存拷贝共享变量最新的值到工作内存,源码使用内存屏障实现可见性通过 lock 保证可见性通过 final 关键字保证可见性final 修饰的量不可变
  总结:解决方案可以分为两类:线程上下文切换:让出cpu时间片,线程切换回导致当前线程本地内存失效;内存屏障:jvm 层面的 storeLoad 内存屏障(下节讲解)2.2 有序性
  对于一个线程的执行代码而言,我们总是习惯性认为代码的执行总是从上到下,有序执行。但为了提供性能,编译器和处理器通常会对指令序列进行重新排序。
  指令重排可以保证串行语义一致,但没有义务保证多线程间的语义也一致。即可能产生"脏读",简单说,两行以上不相干的代码在执行的时候有可能先执行的不是第一条,不见得是从上到下的顺序执行,执行顺序会被优化。
  JVM 能根据处理器特性(CPU多级缓存系统、多核处理器等)适当的对机器指令进行重排序,使机器指令能更符合 CPU 的执行特性,最大限度的发挥机器性能。
  单线程环境里面确保程序最终执行结果和代码顺序执行的结果一致。处理器在进行重排序时必须要考虑指令之间的数据依赖性,多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是无法确定的,结果无法预测。
  在某些情况下可以禁止指令重排。
  如何保证有序性?通过 volatile 关键字保证有序性通过内存屏障保证有序性通过 synchronized 关键字保证有序性通过 Lock 保证有序性2.3 原子性
  指一个操作是不可打断的,即多线程环境下,操作不能被其他线程干扰。例如对于一个静态变量 i =0,线程 A 对它赋值 1,线程 B 对它赋值 -1,那么它要么是 1 要么是 -1,这就是原子性。
  如何保证原子性:通过 synchronized 关键字保证原子性通过Lock保证原子性通过 CAS 保证有序性三、happens-before(多线程先行发生原则)
  在JMM 中,如果一个操作执行的结果需要对另一个操作可见性或者代码重排序,那么这两个操作之间必须存在 happens-before 关系。(逻辑上的先后关系)
  3.1 入门案例
  由这个入门案例可知,第一条语句和第二条语句不能进行排序,否则了能会出现错误。
  happens-before 原则非常重要,它是判断数据是否存在竞争、线程是否安全的主要依据,依靠这个原则,我们解决在并发环境下两操作之间是否可能存在冲突的所有问题。3.2 先行发生原则说明
  如果 Java 内存模型中所有的有序性都仅靠 volatile 和 synchronized 来完成,那么很多操作都将变得非常啰嗦。
  但是我们在编写 Java 并发代码的时候并没有察觉到这一点。
  我们没有时时、处处、次次,添加 Volatile 和 synchronized 来完成程序,这是因为 Java 语言中 JMM 原则下有一个"先行发生"(Happens-Before)的原则限制和规矩,给你定好了规矩。
  这个原则非常重要:它是判断数据是否存在竞争,线程是否安全的非常有用的手段。依赖这个原则,我们可以通过几条简单规则一揽子解决并发环境下两个操作之间是否可能存在冲突的所有问题,而不需要陷入 Java 内存模型苦涩难懂的底层编译原理之中。3.3 总原则(面试答)如果一个操作 happens-before 另一个操作,那么第一个操作的执行结果将对第二个操作 可见 ,而且第一个操作的执行顺序排在第二个操作之前。两个操作之间存在 happens-before 关系,并不意味着一定要按照 happens-before 原则制定的 顺序 来执行。如果重排序之后的执行结果与按照 happens-before 关系来执行的结果一致,那么这种重排序并不非法。3.4 8条3.4.1 次序规则
  一个线程内,按照代码顺序,写在前面的操作先行发生于写在后面的操作;
  前一个操作的结果可以被后续的操作获取。说白了前面一个操作将变量 X 赋值1,那么后面一个操作肯定能知道 X 已经变成 1.3.4.2 锁定规则
  一个unLock操作先行发生于后面((这里的"后面"是指时间上的先后))对同一个锁的lock操作;public class HappenBeforeDemo {     static Object objectLock = new Object();      public static void main(String[] args) throws InterruptedException     {         //对于同一把锁objectLock,threadA一定先unlock同一把锁后B才能获得该锁,   A 先行发生于B         synchronized (objectLock)         {          }     } } 复制代码3.4.3 volatile 变量规则
  对一个volatile变量的写操作先行发生于后面对这个变量的读操作,前面的写对后面的读是可见的,这里的"后面"同样是指时间上的先后。3.4.4 传递规则
  如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;3.4.5 线程启动规则
  Thread对象的start()方法先行发生于此线程的每一个动作3.4.6 线程中断规则
  对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
  可以通过Thread.interrupted()检测到是否发生中断,也就是说你要先调用 interrupt()方法设置中断标志位,我才能监测到中断发送。3.4.7 线程终止规则
  线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread::join()方法是否结束、 Thread::isAlive()的返回值等手段检测线程是否已经终止执行。3.4.8 对象终结规则
  一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始对象没有完成初始化之前,是不能调用finalized()方法的3.5 案例分析
  假设存在线程A和B,线程A先(时间上的先后)调用了setValue(1),然后线程B调用了同一个对象的getValue(),那么线程B收到的返回值 是什么?
  我们就这段简单的代码一次分析happens-before的规则(规则5、6、7、8 可以忽略,因为他们和这段代码毫无关系):
  1 由于两个方法是由不同的线程调用,不在同一个线程中,所以肯定不满足程序次序规则;
  2 两个方法都没有使用锁,所以不满足锁定规则;
  3 变量不是用volatile修饰的,所以volatile变量规则不满足;
  4 传递规则肯定不满足;
  所以我们无法通过happens-before原则推导出线程A happens-before线程B,虽然可以确认在时间上线程A优先于线程B指定,但就是无法确认线程B获得的结果是什么,所以这段代码不是线程安全的。那么怎么修复这段代码呢?把getter/setter方法都定义为synchronized方法把value定义为volatile变量,由于setter方法对value的修改不依赖value的原值,满足volatile关键字使用场景3.6 总结
  在Java 语言里面,Happens-Before 的语义本质上是一种可见性。
  A Happens-Before 意味着 A 发生过的事情对 B 来说是可见的,无论 A 事件和 B 事件是否发生在同一个线程里。
  JMM 的设计分为两部分:一部分是面向我们程序员提供的,也就是 happens-before 规则,它通俗易懂的向我们程序员阐述了强内存模型,我们只要理解 happens-before 规则,就可以编写并发安全的程序了.另一部分是针对 JVM 实现的,为了尽可能少的对编译器和处理器做约束从而提高性能,JMM 在不影响程序执行结果的前提下对其不做要求,即允许优化重排序。我们只需要关注前者就好了,也就是理解 happens-before 规则即可,其他繁杂的内容有 JMM 规范结合操作系统给我们搞定,我们只写好代码即可。四、Volatile4.1 Volatile 关键字保证的可见性
  volatile 字面意思是易变的,不稳定的,在 Java 中是个关键字,作为一个类型修饰符,使用方式如下static volatile int i=0; 复制代码
  其目的是告诉我们,该变量是极有可能多变的,不能随意变动目标指令,并保证该变量上操作的原子性。volatile 修饰的变量有可见性,其含义是变量被修改后,应用程序范围内的所有线程都能够直到这个改动volatile 是非排他的,常常用于多线程的共享变量,在一定条件下,它比锁更合适,性能开销比锁更少
  特点:具备可见性、有序性,不具备原子性。
  JMM 下 Volatile 的内存语义是怎样的?当写一个 volatile 变量时,JMM 会把该线程对应的本地内存中的共享变量值立即刷新回到主内存中当读一个 volatile 变量时,JMM 会把该线程对应的本地内存设置为无效,直接从主内存中读取共享变量。所以,volatile 的写内存语义是直接刷新到主内存中,读的内存语义是直接从主内存中读取的。4.2 内存屏障
  volatile 是通过内存屏障保证它的可见性和有序性的。
  那么什么是屏障呢?生活中的例子就是一个栅栏,一个红绿灯通过这个控制人流,不允许我们随意乱窜,从而保证人流车辆的顺序。4.2.1 重排序
  重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段,有时候会改变程序语句的先后顺序。
  例如:int i = 0;               boolean flag = true; i = 1;                //语句1   flag = fasle;          //语句2 复制代码
  语句1和语句2的执行顺序有可能是先 1后2,也可能是先2 后1 ,这样因为它们数据没有依赖性,重排序后的指令绝对不能改变原有的串行语义。
  【注意】:
  ① 如果存在数据依赖关系,例如语句1定义 i=1;语句2定义 i=2,那么就不能重排序。
  ② 在多线程下,对存在控制依赖的操作重排序,可能会改变程序执行结果, 这时候需要内存屏障来保证可见性。
  【拓展】
  重排序的分类和执行流程
  编译器优化的重排序: 编译器在不改变单线程串行语义的前提下,可以重新调整指令的执行顺序
  指令级并行的重排序: 处理器使用指令级并行技术来讲多条指令重叠执行,若不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序
  内存系统的重排序: 由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是乱序执行
  数据依赖性:若两个操作访问同一变量,且这两个操作中有一个为写操作,此时两操作间就存在数据依赖性。4.2.2 内存屏障
  内存屏障,也称内存栅栏,是一类同步屏障指令,是 CPU 或编译器在对内存随机访问的操作中的一个同步点,使得此点之前的所有读写操作都执行后才可以执行此点之后的操作,避免代码重排序。
  内存屏障其实就是一种 JVM 指令,Java 内存模型的重排规则会要求 Java 编译器在生成 JVM 指令时插入特定的内存屏障指令,通过这些内存屏障指令,Volatile 实现了 Java 内存模型中的可见性和有序性
  内存屏障之前的所有写操作都要回到主内存,内存屏障之后的所有读操作都能获得内存屏障之前的所有写操作的最新结果(实现了可见性) 。
  写屏障(Store Memory Barrier):在写指令之后插入写屏障,强制把写缓冲区的数据刷回到主内存中
  读屏障(Load Memory Barrier):在读指令之前插入读屏障,让工作内存当中的缓存数据失效,重新回到主内存中获取最新数据4.2.3 分类
  volatile 变量规则:
  屏障插入策略1、在每个 Volatile 写操作的前面插入一个 StoreStore 屏障禁止前面的普通写和下面的volatile 写重排序2、在每个 Volatile 写操作的后面插入一个 StoreLoad 屏障防止上面的 volatile 写与下面可能有的 volatile 读写重排序
  3、在每一个 Volatile 读操作后面插入一个 LoadLoad 屏障禁止下面的所有普通读操作和上面的 volatile 读重排序4、在每个 volatile 读操作后面插入一个 LoadStore 屏障禁止下面所有的普通写操作和上面的volatile 读重排序
  4.3 volatile 特性4.3.1 保证可见性
  保证不同线程对某个变量完成操作后结果及时可见,即该共享变量一旦改变了就能通知到其他线程获取主内存的值。
  案例:不加 volatile,没有可见性,程序无法停止加了 volatiel,保证可见性,程序可以停止。public class VolatileTest {      static volatile boolean flag =true;     public static void main(String[] args) {         new Thread(()->{             System.out.println("come in");             while (flag){              }             System.out.println("flag to false");         }).start();         try {             Thread.sleep(1000);         } catch (InterruptedException e) {             e.printStackTrace();         }         flag=false;         System.out.println("main flag ="+flag);     } } 复制代码4.3.2 不保证原子性
  对于 volatile 变量具备可见性,JVM 只是保证从主内存加载到线程工作内存的值是最新的,也仅是数据加载时是最新的。但是多线程环境下,"数据计算" 和数据赋值操作可能多次出现,若数据在加载之后,若主内存 volatile 修饰变量发生修改之后,线程工作内存中的操作将会作废去读主内存最新值,操作出现丢失问题。即各个线程私有内存和主内存公共内存中的变量不同步,进而导致数据不一致。
  对于多线程修改主内存共享变量的场景必须使用加锁同步。
  对于 volatile 变量,JVM 只是保证从主内存加载到线程工作内存的值是最新的,也只是数据加载时是最新的。
  如果第二个线程在第一个线程读取旧值和写回新值期间读取 i 的域值,也就造成了线程安全问题。4.3.3 通过禁止指令重排保证有序性
  对于 volatile 修饰的变量的读写操作,都会加入内存屏障。每个 volatile 写操作前面都会加 storeStore 屏障,禁止上面的写与它重排序每个 volatile 写操作后面都会加 StoreLoad 屏障,禁止下面的读与它重排序每个 volatile 读操作后面都会加 LoadLoad 屏障,禁止下面的读与它重排序每个 volatile 读操作后面都会加 LoadStore 屏障,禁止下面的写与它重排序
  4.4 使用场景
  1、单一赋值可以,复合运算不行(i++)volatile boolean flag=false; 复制代码
  2、状态标志,判断业务是否结束/**  *  * 使用:作为一个布尔状态标志,用于指示发生了一个重要的一次性事件,例如完成初始化或任务结束  * 理由:状态标志并不依赖于程序内任何其他状态,且通常只有一种状态转换  * 例子:判断业务是否结束  */ public class UseVolatileDemo {     private volatile static boolean flag = true;      public static void main(String[] args)     {         new Thread(() -> {             while(flag) {                 //do something......             }         },"t1").start();          //暂停几秒钟线程         try { TimeUnit.SECONDS.sleep(2L); } catch (InterruptedException e) { e.printStackTrace(); }          new Thread(() -> {             flag = false;         },"t2").start();     } } 复制代码
  3、开销较低的读、写锁策略
  当读远多于写public class UseVolatileDemo {     /**      * 使用:当读远多于写,结合使用内部锁和 volatile 变量来减少同步的开销      * 理由:利用volatile保证读取操作的可见性;利用synchronized保证复合操作的原子性      */     public class Counter     {         private volatile int value;          public int getValue()         {             return value;   //利用volatile保证读取操作的可见性               }         public synchronized int increment()         {             return value++; //利用synchronized保证复合操作的原子性                }     } } 复制代码
  4、DCL 双端锁的发布
  双重检查锁定public class SafeDoubleCheckSingleton {     private static SafeDoubleCheckSingleton singleton;     //私有化构造方法     private SafeDoubleCheckSingleton(){     }     //双重锁设计     public static SafeDoubleCheckSingleton getInstance(){         if (singleton == null){             //1.多线程并发创建对象时,会通过加锁保证只有一个线程能创建对象             synchronized (SafeDoubleCheckSingleton.class){                 if (singleton == null){                     //隐患:多线程环境下,由于重排序,该对象可能还未完成初始化就被其他线程读取                     singleton = new SafeDoubleCheckSingleton();                 }             }         }         //2.对象创建完毕,执行getInstance()将不需要获取锁,直接返回创建对象         return singleton;     } } 复制代码五、小结
  1、由于 CPU 并非直接操作内存,而是将内存的数据放到高速缓存区中,通过高速缓冲区解决了主内存与 CPU 之间的一个速率读取问题。但因为高速缓存区和主存各有一个数据,带来了缓存不一致问题。
  2、为了解决缓存不一致问题,Java 推出了 JMM 规范,目的是解决由于多线程通过共享内存通信时,产生的主内存和工作内存数据不一致性问题、编译器对代码的重排序等问题。
  3、那么什么是 JMM 规范呢?它是通过一组规则来决定一个线程对共享变量的写入何时对另一个线程可见。它有三大特性:可见性、有序性、原子性。可见性即修改的变量对另一个线程可见,有序性是由于 JVM 会对机器指令进行重排序,多线程下回出现乱序现象原子性是一个线程的操作不能被另一个线程打断
  4、那为了解决这三大问题,是不是我们都要通过加锁或 volatile 等方式解决呢?答案不是的,JMM 给我们提供了 happens-before 原则来辅助我们保证程序的原子性、可见性、有序性问题,它能够判断数据是否存在竞争、线程是否安全的依据。
  5、而 volatile 它能够保证可见性和有序性,它通过内存屏障实现有序性,通过汇编指令后的 lock 前缀,将数据刷新回主存实现可见性,但不能保证原子性。

妇科检查的最佳时间是什么时候?想做妇科检查,但是不知道什么时间去?其实很简单,如果你不舒服了,那么立马就去查。如果你并不是有什么不舒服,而是想作为健康体检,看一看自己的身体是否存在问题,那么可以在月经结束后37有什么好的时间管理软件?时光序,让日程管理用最酷炫的方式,最好的日程管理软件,没有之一桌面透明插件,直接用颜色显示不同类型事项,文字提示经典桌面四象限,重要紧急事项一目了然一月一周一天,酷炫展示时间都去哪期中考试成绩出来后,作为家长的你会在乎孩子的成绩吗?期中考试成绩出来后,作为家长会不会在乎孩子的成绩?说不在乎都是假的,只要真正培养孩子的父母,都会很在乎!本人作为一名教师,同时也是一位家长,就很在乎孩子的成绩。但是,在乎是一回事,被家长先入为主的认为自己性格不好,是什么样的体验?谢邀!性格嘛!其实只有自己最了解自己吧!父母对你的了解,也并不是全部,因为他们也并不是事无巨细地知道你的内心。其次,被家里人认为性格不好,其实我觉得并没什么,因为他们起码还是你的亲去西双版纳住一段时间,怎么住比较合适?我也刚到几天,版纳出租房很多,建议到达后先找个客栈住三天,自己在出去找房,我在曼听公园一墙之隔住,风景优美,静,空气好,住半年每月800有独立卫浴,网络,床,衣柜,电视,锅碗瓢盆儿洛阳会在隋唐故城遗址上修复隋唐故城吗,你怎么看?谢谢邀请!我在回答问题之前,必须要声明一点,各种地域攻击分子,如果你想找骂的话,我会奉陪!如果,有不同意见愿意交流,我欢迎!洛阳城的缔造者周公画像洛阳,是中国为数不多的几个重要的古国内哪些城市市区可以看到雪山?我的家乡内蒙古自治区呼伦贝尔根河市,中国冷极。一年有半年都在下雪,现在四月还在下雪。我国有着三座可以再市区里面不借助任何的工具就能够看到雪山的城市,在市区看到雪山想想就觉得是一种非宇宙到底有边际吗?如果有边际,那边际是什么东西?是一堵墙吗?首先要明白什么是宇宙?清楚宇宙是什么?然后才知道宇宙是否有边际。因为人们的宇宙理念不同,认识不一样,理解不统一,个人认知,宇宙固有,自身无始终,本体无限,生命力永恒。所以宇宙沒有边宿迁有哪些有趣的地名?洋河双沟以酒为名。宿迁市是以酒闻名,洋河双沟两大名酒,已经是宿迁的招牌,也是全国人民比较热爱的酒类产品之一。而洋河镇与双沟镇就是以酒名而定的地名。洋河蓝色经典双沟珍宝坊,以及打造出互联网废品回收加盟靠谱吗?废话不多说!直接上干货!近期有关注再生资源回收行业的兄弟们不难发现,各大平台自媒体都打着各种互联网废品回收互联网再生资源像叫外卖一样卖废品等等字眼。互联网回收行业一下子就成火遍全网为什么国产手机越卖越贵了?从我个人来讲,国产手机越来越贵了这个结论我是不认可的,至少经不起全方位的论证,显得片面且不严谨。国产手机真的越来越贵?这应该是小米从1999到9999后大家的固化印象,再加上前面有
冬天的故宫,才能满足挑剔的旅行者很多人去过故宫,但却少有人亲历感受过冬天的故宫。寒冷是阻碍人们领略美景的主要原因。每年的夏秋季节,北京的气温宜人,故宫的色彩极其华丽旖旎,来自全世界的游人络绎不绝,有时甚至要排队。漫步普吉老城探索6大普吉老街景点与故事移民文化是普吉老城(OldPhuketTown)最重要的文化根源,普吉岛(PhuketIsland)于16世纪起发现丰富的锡矿,曾吸引马来西亚人阿拉伯人缅甸人暹罗人福建人葡萄牙人前中免集团海口三亚国际免税城共同启动钟表与奇迹海南高级钟表展12月2日,由中免集团和瑞士高级制表基金会(FHH)联合举办的第三届钟表与奇迹海南高级钟表展在cdf海口国际免税城cdf三亚国际免税城共同启幕。海南省商务厅一级巡视员姚磊副厅长程瑗用山西的方式打开黄河这本书,里面埋藏了多少宝藏?黄河一路奔流流过长河落日流过大漠孤烟流过孤城万仞流过白日依山山西依偎在黄河的臂弯黄河之魂在这里流淌流过大地也流过历史山西与黄河共舞见证着中华文明的诞生与成长这里保存着文明的星火约2走进吉普的世界,在山水间游转小记作品黄正好八桂小记,带你看世界!作品展示实践活动探索吉普车文化八桂小记者江南民大附小四年级指导老师晏泽11月26日,八桂小记者团来到金斯源4S店探寻吉普车的秘密。现场,我们参观了自由光和指挥夏日海边白色的沙滩上有白色的雏菊取图看主页。在这里,我要说明的是一些东西,不是我故意要吊人胃口,实在是因为我真的不知道该怎么描述,就连我自己都不敢相信自己所看到的事物会如此之美。这个世界,果然还有这样的东西存在吗藏着奥秘的布达拉宫我们来聊聊这个世界上最神秘的宫殿布达拉宫。看到布达拉宫啊!许多人都感觉非常熟悉,因为你几乎天天都能看到它,不相信吗?打开你手中的50元人民币看看那上面就是布达拉宫。那为什么说它是这诗情画意的中国中华名山五岳五岳之长泰山(一)诗情画意的中国中华名山五岳五岳之长泰山(一)汪鹤年中国最早的诗歌总集诗经中就有泰山岩岩,鲁邦所瞻的歌吟。汉武帝登临泰山后,竟一口气地说出它的诸多妙处高矣极矣大矣特矣壮矣赫矣骇矣惑矣长泰山重村入选2022世界旅游联盟旅游助力乡村振兴案例福建日报新福建客户端12月12日讯(记者李妙珠)近日,2022世界旅游联盟旅游助力乡村振兴案例由世界旅游联盟和中国国际扶贫中心合作发布。整书收录了全国50个优秀案例,由漳州市文旅局重温旧影,刚过门的小妾婀娜多姿,图九正妻天庭饱满,一脸旺夫在大清覆灭以前,中国男人享有一妻多妾的权力,这是后世所艳羡的。只是封建社会等级森严,并不是每个男人都可以在外面花天酒地,妻妾成群。只有那些大人物,土豪,才有资格纳妾,穷苦人家连个老23年前贵州缆车失事,2岁孩子失去父母后被韩红收养,如今怎样了读者朋友们,在阅读文章之前,辛苦您动动小手点击一下关注,我们将持续更新历史故事,既方便您后续的阅读,又可以与志同道合的读友进行讨论,感谢您的支持。1999年10月3日,一对恩爱异常