前些天与一位朋友技术交流,朋友在招人面试时想到一个问题,JVM垃圾回收时,会复制存活的对象到不同的区域。比如从新生代复制到老年代,在此过程中,被复制的对象的地址是否变了呢?对他提出的这个问题很感兴趣,深入研究了一下,便有了这篇文章。
老王:小陈啊,上一章我们讲了usafe是个啥东西,以及unsafe提供的几大类的功能
CAS算法的作用:解决多线程条件下使用锁造成性能损耗问题的算法,保证了原子性,这个原子操作是由CPU来完成的 CAS的原理:CAS算法有三个操作数,通过内存中的值(V)、预期原始值(A)、修改后的新值。 (1)如果内存中的值和预期原始值相等, 就将修改后的新值保存到内存中。 (2)如果内存中的值和预期原始值不相等,说明共享数据已经被修改,放弃已经所做的操作,然后重新执行刚才的操作,直到重试成功。 注意: (1)预期原始值(A)是从偏移位置读取到三级缓存中让CPU处理的值,修改后的新值是预期原始值经CPU处理暂时存储在CPU的三级缓存中的值,而内存指定偏移位置中的原始值。 (2)比较从指定偏移位置读取到缓存的值与指定内存偏移位置的值是否相等,如果相等则修改指定内存偏移位置的值,这个操作是操作系统底层汇编的一个原子指令实现的,保证了原子性
let命令 基本用法 ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。 'use strict'; { let a = 10; var b = 1; } a // 报错,ReferenceError: a is not defined. b // 1 不存在变量提升 let不像var那样会发生“变量提升”现象。所以,变量一定要在声明后使用,否则报错。 'use strict'; console.log(foo); // 输出unde
在 Java 多线程并发编程中,经常遇到 volatile 使用场景,如 JDK 并发容器 ConcurrentHashMap 的 Node 类,其 V 和 next 属性就是用 volatile 修饰的。
其实在Java中,String类被final修饰,主要是为了保证字符串的不可变性,进而保证了它的安全性。那么final到底是怎么保证字符串安全性的呢?接下来就让我们一起来看看吧。
volatile相关的知识其实自己一直都是有掌握的,能大概讲出一些知识,例如:它可以保证可见性;禁止指令重排。这两个特性张口就来,但要再往深了问,具体是如何实现这两个特性的,以及在什么场景下使用volatile,为什么不直接用synchronized这种深入和扩展相关的问题,就回答的不好了。因为volatile是面试必问的知识,所以这次准备把这部分知识也给啃掉。
老王:是啊,之前我们只是简单介绍了Atomic的体系,今天我们就要进入Atomic底层原理的的学习了,首先我们从AtomicInteger这个比较简单的原子类开始,在说AtomicInteger的底层原理之前呢,我先给你看两个例子:
生命周期和线程一样,主要是记录该线程Java方法执行的内存模型。虚拟机栈里面放着好多栈帧。注意虚拟机栈,对应是Java方法,不包括本地方法。
JMM即Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等。 JMM体现在以下几个方面
这些问题对于认真学习java的人都要必知的,当然如果你只是初学者就没必要那么严格了,那如果你认为自己已经超越初学者了,却不很懂这些问题,请将你自己重归初学者行列。
volatile 是 Java 的一个关键字,它提供了一种轻量级的同步机制。相比于重量级锁 synchronized,volatile 更为轻量级,因为它不会引起线程上下文的切换和调度。
上一篇学习了synchronized的关键字,synchronized是阻塞式同步,在线程竞争激烈的情况下会升级为重量级锁,而volatile是一个轻量级的同步机制。
基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。引用数据类型的值是保存在内存中的对象,JS不允许直接访问内存中的位置,所以在操作的时候操作的是对象的引用;因此是引用数据类型是按照引用访问的。
在高并发的业务场景下,线程安全问题是必须考虑的,在JDK5之前,可以通过synchronized或Lock来保证同步,从而达到线程安全的目的。但synchronized或Lock方案属于互斥锁的方案,比较重量级,加锁、释放锁都会引起性能损耗问题。
public class Singleton { private static Singleton singleton;
这一章我们进一步深入学习共享变量在多线程间的【可见性】问题与多条指令执行时的【有序性】问题
创建型模式之单例模式(Singleton) 什么是单例模式 该类只有一个实例 构造方法是私有的 有一个获取该类对象的静态方法getInstance() 应用场景 一个国家只有一个主席 如果此时的限定必须是抽象出来的类只能是一个对象,这个时候就需要使用单例模式 懒汉式 什么是懒汉式 懒汉式是当用到这个对象的时候才会创建,即是在getInstance()方法创建这个单例对象 优缺点 只有用到的时候才会创建这个对象,因此节省资源 线程不安全 我们知道一旦我们使用了懒汉式就是在getInstance()方法中创建这
在上篇文章中,我们介绍到在多线程环境下,如果编程不当,可能会出现程序运行结果混乱的问题。
地址:https://juejin.im/post/59f8231a5188252946503294
volatile是Java提供的一种轻量级的同步机制。Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量,相比于synchronized(synchronized通常称为重量级锁),volatile更轻量级,因为它不会引起线程上下文的切换和调度。但是volatile 变量的同步性较差(有时它更简单并且开销更低),而且其使用也更容易出错。
对于这个系列里的问题,每个学JAVA的人都应该搞懂。当然,如果只是学JAVA玩玩就无所谓了。如果你认为自己已经超越初学者了,却不很懂这些问题,请将你自己重归初学者行列。内容均来自于CSDN的经典老贴。 问题一:我声明了什么! String s = "Hello world!"; 许多人都做过这样的事情,但是,我们到底声明了什么?回答通常是:一个String,内容是“Hello world!”。这样模糊的回答通常是概念不清的根源。如果要准确的回答,一半的人大概会回答错误。 这个语句声明的是一个指向对象的引用,
let和var声明变量的区别: 1.let所声明的变量只在let命令所在的代码块内有效。(块级作用域)
如果多个线程对同一个共享数据进行访问而不采取同步操作的话,那么操作的结果是不一致的。
这一章主要是讲解volatile的原理,在开始本文前,我们来看一张volatile的思维导图,先有个直观的认识。
在Java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉。
类文件首先需要经过类加载子系统,进行加载,进类信息等加载到运行时数据区,生成Klass的实例。
作为一门面向对象编程的语言,Java中所有的概念和行为都建立在对象之上。这也就意味着,Java程序的编写实际上就是定义和操作各种不同类型的对象。而为了更好的定义和操作这些对象,我们就需要全面的了解一下对象生成的过程。
结论:这种情况下,不管是用strong还是copy修饰的对象,其指向的地址都是originStr的地址。
并发编程,为了保证数据的安全,需要满足三个特性:原子性、可见性、有序性。Java 中可以通过锁和 CAS 的方式来实现原子操作。
在整理线程安全相关东西之前,我们来了解一下,一个对象在HotSpot虚拟机中的内存布局;
在上一篇文章中我们已经知道线程是 通过主内存 去进行线程间的 隐式通信 的,而线程对共享变量的写操作在 工作内存 中完成,由JMM控制 共享变量由工作内存写回到主内存的时机 。
1.java是如何管理内存的 java的内存管理就是对象的分配和释放问题。(其中包括两部分) 分配:内存的分配是由程序完成的,程序员需要通过关键字new为每个对象申请内存空间(基本类型除外),所有的对象都在堆(Heap)中分配空间。 释放:对象的释放是由垃圾回收机制决定和执行的,这样做确实简化了程序员的工作。但同时,它也加重了JVM的工作。因为,GC为了能够正确释放对象,GC必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。 2.什么叫java的内存泄露 在java中,
1、static关键字 1.1、static关键字可以修饰什么?static使用的注意事项有哪些?static关键字的特点?使用static存在什么问题? 可以用来修饰:成员变量,成员方法,代码块,内部类等。具体如下所示 修饰成员变量和成员方法 被 static 修饰的成员属于类,不属于单个这个类的某个对象,被类中所有对象共享,可以并且建议通过类名调用。 被static 声明的成员变量属于静态成员变量,静态变量存放在Java内存区域的方法区。 静态代码块 静态代码块定义在类中方法外,静态代码块在非静态
令重排序:java语言规范规定JVM线程内部维持顺序化语义。即只要程序的最终结果 与它顺序化情况的结果相等,那么指令的执行顺序可以与代码顺序不一致,此过程叫指令的 重排序。
计算机在执行程序的时候,每条指令都是在CPU中执行的,执行完了把数据存放在主存当中,也就是计算机的物理内存。 刚开始没问题,但是随着CPU技术的发展,执行速度越来越快。而由于内存的技术并没有太大的变化,导致从内存中读写数据比CPU慢,浪费CPU时间。 于是在CPU和内存之间增加高速缓存。这样就引入新的问题:缓存一致性。在多核CPU中,每个核的自己的缓存中,关于同一个数据的缓存内容可能不一致。 除了这种情况,还有一种硬件问题也比较重要。那就是为了使处理器内部的运算单元能够尽量的被充分利用,处理器可能会对输入代码进行乱序执行处理。这就是处理器优化。 除了现在很多流行的处理器会对代码进行优化乱序处理,很多编程语言的编译器也会有类似的优化,比如Java虚拟机的即时编译器(JIT)也会做指令重排。
首先看一看AtomicInteger当中常用的自增方法 incrementAndGet:
我们之前了解过了 AtomicInteger、AtomicLong、AtomicBoolean 等原子性工具类,下面我们继续了解一下位于 java.util.concurrent.atomic 包下的工具类。
分配 :内存的分配是由程序完成的,程序员需要通过关键字new 为每个对象申请内存空间 (基本类型除外),所有的对象都在堆 (Heap)中分配空间。 释放 :对象的释放是由垃圾回收机制决定和执行的,这样做确实简化了程序员的工作。但同时,它也加重了JVM的工作。因为,GC为了能够正确释放对象,GC必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。
界面间传值场景 1.由前往后属性传值.在后一个界面中定义属性(属性类型和数据类型一致) 2.当push到下一个界面之前给属性赋值3.在下一个界面中,相应的控件从属性中获取数据 2. 由前往后 协议代理,1.在后一个界面定义协议(协议中定一个传值方法,方法由參数,參数类型和传输类型一致)2.在后一个界面定义代理属性,3.在前一个界面中设置代理4.代理对象的类服从协议 3.多界面传值(即能够从前往后,也能够从后往前) 单例一个类仅仅有一个对象 1.新建一个单例类 2.加入便利构造器方法而且保证该方法不管滴哦用多少次,返回的地址都是一样的 3.为该类加入属性,存储要传递的数据 4.传递数据时把数据存储在单例属性中 5.当须要该属性时,直接从单例属性中获取 单例 为了保证该类仅仅有一个对象,我们用静态变量来储存对象的地址,一旦指针变量为空,则创建对象,否则直接将原有的地址返回,可是alloc的控件无法确定释放的时机.所以仅仅有alloc不release,会造成内存泄露,单例是用来解决特定的问题,万不得已尽量不要使用单例 导航控制器管理的多视图控制I之间存在层级关系,即:后一个界面的显示内容要依赖与前一个界面,假设前一个界面显示的内容依赖与后一个界面,使用心的是u弹出方式,模态,可是此时弹出的视图控制器并不受原有导航控制器管理
在面试、并发编程、一些开源框架中总是会遇到 volatile 与 synchronized 。synchronized 如何保证并发安全?volatile 语义的内存可见性指的是什么?这其中又跟 JMM 有什么关系,在并发编程中 JMM 的作用是什么,为什么需要 JMM?与 JVM 内存结构有什么区别?
老王:开讲啦,开讲啦,小陈快来上课,今天我们就来探讨一下synchronized底层到底是怎么加锁的?
以整型加法为例,我们来看看在计算机内部,CPU(中央处理器)是如何配合其他硬件进行计算的。
原型模式的结构 原型模式包含以下3个角色: •Prototype(抽象原型类) •ConcretePrototype(具体原型类) •Client(客户类)
不知朋友们在编写多线程代码时,对于共享内存变量是否很好的处理呢,接下来我们将介绍volatile语义、特性、和使用。
java 文件通过javac编译成class文件,这种代码我们称之为字节码(中间码), 由JVM去加载字节码这个过程。
领取专属 10元无门槛券
手把手带您无忧上云