java中的异常和处理详解 Java如何解决可见性和有序性的问题?
Java如何解决可见性和有序性的问题?
首先,我们需要了解为什么会有 "能见度和和 "时机与时机问题,然后让 让我们看看Java是如何解决这两个问题的。
可见性和时间问题导致以下原因:
抢占式任务执行:现代CPU多任务执行模式是 "先发制人 ",它的总控制权在操作系统手里,操作系统会把执行时间片依次分配给需要CPU执行的任务。超过时间后,操作系统将剥夺当前任务的CPU访问权,将其放在队列的末尾,最后分配时间片...
存储速度差异:每个存储的执行速度不同。越靠近CPU,存储速度越快,相对容量越小。不可能一次把执行程序需要的所有数据都加载到寄存器中,所以有一个加载和存储的过程,这就影响了所谓的 "能见度和
指令重排:现代微处理器大多会采用乱序执行的方法(简称OoOE或oOE),在条件允许的情况下直接运行当前能够立即执行的后续指令,避免等待获取下一条指令所需的数据。通过乱序执行技术,处理器可以大大提高执行效率。除了处理器,常见Java运行时环境中的JIT编译器也做指令重排序操作,即生成的机器指令与字节码指令的顺序不同。
解决问题的方法很简单,就是强制多线程单线程化。
只有两种解决方案:
记忆障碍
锁
让 让我们来看看JVM的内存模型,我们将基于这个模型来简单解释一下。
内存屏障内存屏障是通过volatile关键字在Java中体现的。Volatile将在适当的地方添加以下四个内存屏障。
LoadLoad barrier:对于这样的语句,Load1 Load Load2,保证Load1要读取的数据在Load2要读取的数据和后续读取操作被访问之前被读取。
StoreStore barrier:对于这样一个语句,Store1 StoreStore Store2,保证Store1的写操作在Store2和后续写操作执行之前对其他处理器可见。
LoadStore barrier:对于这样一个语句,Load1 LoadStore Store2,在Store2和后续的写操作被刷出之前,Load1要读取的数据保证被完全读取。
StoreLoad barrier:对于这样的语句Store1 StoreLoad Load2,在执行Load2和所有后续读取操作之前,Store1的写入保证对所有处理器可见。它的开销是四个障碍中最大的。在大多数处理器实现中,这种屏障是通用屏幕。屏障,具有其他三种记忆屏障的功能。
内存屏障只能保证可见性,而不能保证计时。也就是说,内存屏障只是解决了线程A修改的内容可以被线程B立即读取的问题。
Java中的锁根据性质可以分为悲观锁和乐观锁。悲观锁基于锁指令实现,乐观锁基于CAS实现。
悲观锁是通过monitorenter和monitorexit两个指令实现的,这两个指令之间的指令不能重排和互斥。假设线程A和线程B同时执行一段代码,线程A首先通过monitorenter获得锁,那么线程B只能在线程A执行monitorexit之前等待。
CAS是CompareAndSet,Java是通过spinning和CPU级指令实现的。有关详细信息,请参考JUC实施。假设有一个变量c,初始值为3。线程A和线程B同时修改这个变量。A和B同时得到变量C的值。a首先修改它并将值更改为4。b试图修改它,但是发现c的值现在是4而不是3,于是他等待spin,然后重新进行修改操作,将4改为5。
ThreadLocal最后说ThreadLocal。ThreadLocal是局部线程变量,即在线程中直接使用公共变量,修改不影响外界。它远远没有解决 "能见度和和 "时机与时机。它只保证当前线程中的修改不影响其他线程,其他线程的修改不影响当前线程。
java中的main函数抛出的异常由谁处理?
java中main函数抛出的异常由JVM(java虚拟机)处理。
在java程序中,如果异常被抛出,直到在try{}catch时被捕获;如果仍然没有捕获到main方法(main method),那么异常将由java虚拟机(java运行时环境)处理。
版权声明:本文内容由互联网用户自发贡献,本站不承担相关法律责任.如有侵权/违法内容,本站将立刻删除。