volatile和synchronized及其区别、类加载的过程、java异常、线程安全-Java基础

1、volatile和synchronized及其区别

  1. volatile

volatile 是关键词之一,声明变量,该变量可以随时会被别的线程修改,使用volatile 修改的变量会强制将修改的值写入主存,主存中的值更新会使得缓存的值无效。具有可见性、有序性,不具备原子性,也就不能保证线程安全。

适用于对变量的写操作不依赖于当前值,对变量读取操作不依赖于非volatile 变量。

适用于读多写少的场景;

可用作状态的标志;

不会让线程阻塞,响应速度比synchronized 高;

volatile 用于多线程同步中,可保证读取得可见性;

JVM保证从主内存加载到线程工作内存的值事最新的;

2)synchronized

一个使用场景:开启10个进程,每个进程累加100000000,结果却不是10*1000000;而且每次数据结果都是不一样的。(一个应用需要很多线程,而且如果数据量较大,计算较多,常常会出现这种问题,需要进行线程同步)。

导致这种结果的原因主要是主内存和线程的工作内存而导致的内存可见性问题,,以及重排序导致的问题,进一步知道happens-before规则。线程的运行都作用在自己的栈空间,如果不进行共享数据,就好导致进程不同步的问题。线程数据共享还要考虑数据的安全问题,如果每个线程所操作的都是最新数据,那么线程安全又成了问题。所以需要synchronized 使得线程依次排队操作共享数据。synchronized 也是其他并行容器实现的基础。

作用:锁住实例方法中的实例对象;静态方法中锁住类对象;同步代码块,锁住该类的实例对象;同步代码块,锁住该类的类对象;同步代码块,锁住的是配置的实例对象;

不赘述了,推荐一篇文章:https://www.jianshu.com/p/d53bf830fa09

3)volatile 和 synchronized 的区别

1)volatile本质是告诉jvm当前变量再寄存器中的值是不确定的,需要从主存在中读取;

synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住;

  1. volatile 仅能使用再变量级别; synchronized 可以使用在变量和方法;
  2. Volatile仅能实现变量的修饰可见性,但不具有原子性;而synchronized则可以保证变量的修改可见性和原子性;
  3. volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化;
  1. 类加载的过程

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中准备、验证、解析3个部分统称为连接(Linking)。如图所示。

加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定)。以下陈述的内容都已HotSpot为基准。

加载

在加载阶段(可以参考java.lang.ClassLoader的loadClass()方法),虚拟机需要完成以下3件事情:

1)通过一个类的全限定名来获取定义此类的二进制字节流(并没有指明要从一个Class文件中获取,可以从其他渠道,譬如:网络、动态生成、数据库等);

2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;

3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;

加载阶段和连接阶段(Linking)的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,但这些夹在加载阶段之中进行的动作,仍然属于连接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。

验证

验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

验证阶段大致会完成4个阶段的检验动作:

1)文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以魔术0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。

2)元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。

3)字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。

4)符号引用验证:确保解析动作能正确执行。

验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在堆中。其次,这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为:

 public static int value=123;        

那变量value在准备阶段过后的初始值为0而不是123.因为这时候尚未开始执行任何java方法,而把value赋值为123的put static指令是程序被编译后,存放于类构造器()方法之中,所以把value赋值为123的动作将在初始化阶段才会执行。

至于“特殊情况”是指:public static final int value=123,即当类字段的字段属性是ConstantValue时,会在准备阶段初始化为指定的值,所以标注为final之后,value的值在准备阶段初始化为123而非0.

执行static块代码,先加载非静态的,再加载静态的。

解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

初始化

类初始化阶段是类加载过程的最后一步,到了初始化阶段,才真正开始执行类中定义的java程序代码。在准备极端,变量已经付过一次系统要求的初始值,而在初始化阶段,则根据程序猿通过程序制定的主管计划去初始化类变量和其他资源,或者说:初始化阶段是执行类构造器<clinit>()方法的过程.

<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块static{}中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。

原文链接:http://www.importnew.com/18548.html

  1. java异常

异常分为运行时异常RuntimeException,非运行异常也叫检查异常CheckedException和error。

  1. error是系统异常,只能重启解决。
  2. 非运行时异常需要自己捕获;

IOException

SqlException

  1. 运行异常是程序运行时虚拟机JVM帮助我们捕获,包括数组溢出、内存溢出、空指针、分母为0;

classCastException类转换异常

ClassNotFoundException

IndexOutOfBoundsException数组越界

NullPointerException空指针异常

ArrayStoreException数组存储异常,即数组存储类型不一致

IO操作的BufferOverflowException异常

 

throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。而throw则是指抛出的一个具体的异常类型

  1. 线程安全

 线程安全概念:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

线程安全问题都是由全局变量及静态变量引起的。

若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

LinkedList 和 ArrayList 都是不同步的,线程不安全;

Vector 和 Stack 都是同步的,线程安全;

Set是线程不安全的;

Hashtable的方法是同步的,线程安全;

HashMap的方法不是同步的,线程不安全;

 线程安全的集合类:喂!SHE!喂是指vector,S是指stack,H是指hashtable,E是指:Eenumeration. Properties(Hashtable的子类)

  1. vector和arraylist都数组实现,vector多了个同步机制,效率也较低;
  2. Stack 堆栈类,先进后出。
  3. hashtable比hashmap多个线程安全;
  4. Eenumeration枚举,相当于迭代器;
  5. stringBuffer线程安全,stringBuilder线程不安全;
  6. TreeSet HashSet都是非安全线程,方法都没有实现安全的机制;
  1. 枚举enum类型

是java5新增的特性,是一种新类型,允许用常量来表示特定的数据片断,而且全部都以类型安全的形式来表示,是特殊的类,可以有成员变量和方法。

  1. jvm垃圾回速分为scanvenge gc 和 full GC,其中full GC触发的条件可能有 老年代满、持久代满、System.gc();
  2. Java序列化

将此对象序列化为文件,并在另外一个JVM中读取文件,进行反序列化,此时对象中的word和i的值?

import java.io.Serializable;

public class test implements Serializable{

/**

 * @author ycy

 */

private static int i = 0;

private String word = " ";

public void setWord(String word){

this.word = word;

}

public void setI(int i){

test.i = i;

}

public static void main(String[] args) {

// TODO Auto-generated method stub

test tt = new test();

tt.setWord("123");

tt.setI(2);

}

}

序列化保存的是对象的状态,静态变量属于类的状态,因此序列化并不保存静态变量,所以i没有改变,还是0.而word变化为“123”.

8、Forward 和 redirect

1)Forward,服务器获取跳转页面内容传递给用户,用户的地址不改变;

客户端跳转,地址栏不改变,执行完页面后不会转向,相当于函数调用,并且可以传递request属性,实际上是对requestDispatcher接口的封装。

2)Redirect ,是服务器转向用户发送转向的地址,地址栏会变成新的地址;

请求重定向,客户端行为,本质上为2次请求,地址栏改变,前一次请求的对象消失。

扫码关注一起随时随地学习!!!就在洋葱攻城狮,更多精彩,等你来!!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洋葱ycy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值