Java并发包
锁机制:通过cas机制保证了当多线程并发时,就算所有的线程都同时访问,但是只会有一个成功,而锁的本质就是,只有一个能操作其他的都“睡觉”,当使用lock是,一定要注意lock与unlock的次数要相等
volatile机制:参考下面的例子,也就是说对volatile修饰的变量的修改不能依赖于当前的值,所以感觉volatile只能使用在标志位了
<span style="font-size:18px;">public class VolatileTest { public static volatile int i; public VolatileTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public static void increase(); Code: 0: getstatic #2 // Field i:I, 把i的值取到了操作栈顶,volatile保证了i值此时是正确的. 3: iconst_1 4: iadd // increase,但其他线程此时可能已经把i值加大了好多 5: putstatic #2 // Field i:I ,把这个已经out of date的i值同步回主内存中,i值被破坏了. 8: return LineNumberTable: line 6: 0 line 7: 8 }</span>
原子变量:也是通过cas机制实现的,cas是什么:compare and swap就是线比较在修改
Thread
ThreadLocal:线程本地变量,或者说是线程的私有变量,这不是解决线程安全问题的解决方法,可以当作一个传值工具,但不建议这么做
public class ThreadLocalTest { static class ResourceClass { public final static ThreadLocal<String> RESOURCE_1 = new ThreadLocal<String>(); public final static ThreadLocal<String> RESOURCE_2 = new ThreadLocal<String>(); } static class A { public void setOne(String value) { ResourceClass.RESOURCE_1.set(value); } public void setTwo(String value) { ResourceClass.RESOURCE_2.set(value); } } static class B { public void display() { System.out.println(ResourceClass.RESOURCE_1.get() + ":" + ResourceClass.RESOURCE_2.get()); } } public static void main(String []args) { final A a = new A(); final B b = new B(); for(int i = 0 ; i < 15 ; i ++) { final String resouce1 = "线程-" + i, resouce2 = " value = (" + i + ")"; new Thread() { public void run() { try { a.setOne(resouce1); a.setTwo(resouce2); b.display(); }finally { ResourceClass.RESOURCE_1.remove(); ResourceClass.RESOURCE_2.remove(); } } }.start(); } } }
与此相对应的,就得说说unsafe类,在并发包的lock中的AQS就是使用的这个来使Thread挂起的
Java对象初始化
Java中的初始化顺序
对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是
(静态变量、静态初始化块)>(变量、初始化块)> 构造器。
JAVA类首次装入时,会对静态成员变量或方法进行一次初始化,但方法不被调用是不会执行的,静态成员变量和静态初始化块级别相同,非静态成员变量和非静态初始化块级别相同。
初始化顺序:先初始化父类的静态代码--->初始化子类的静态代码-->
(创建实例时,如果不创建实例,则后面的不执行)初始化父类的非静态代码(变量定义等)--->初始化父类构造函数--->初始化子类非静态代码(变量定义等)--->初始化子类构造函数
类只有在使用New调用创建的时候才会被JAVA类装载器装入创建类实例时,首先按照父子继承关系进行初始化类实例创建时候,首先初始化块部分先执行,然后是构造方法;然后从本类继承的子类的初始化块执行,最后是子类的构造方法类消除时候,首先消除子类部分,再消除父类部分.
运行以上代码,我们会得到如下的输出结果:
静态变量
静态初始化块
变量
初始化块
构造器
运行一下上面的代码:
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
说明:并不是父类完全初始化完毕后才进行子类的初始化,实际上子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了。
运行上面的代码,会得到如下的结果:
Test--A
静态初始化块
Test--B