JAVA小知识点记录(三)

HashMap、Hashtable、ConccurentHashMap三者的区别
HashMap线程不安全,数组+链表+红黑树
Hashtable线程安全,锁住整个对象,数组+链表
ConccurentHashMap线程安全,CAS+同步锁,数组+链表+红黑树
HashMap的key,value均可为null,其他两个不行。

在JDK1.7和JDK1.8中的区别
在JDK1.8主要设计上的改进有以下几点:

1、不采用segment而采用node,锁住node来实现减小锁粒度。
2、设计了MOVED状态 当resize的中过程中 线程2还在put数据,线程2会帮助resize。
3、使用3个CAS操作来确保node的一些操作的原子性,这种方式代替了锁。
4、sizeCtl的不同值来代表不同含义,起到了控制的作用。
采用synchronized而不是ReentrantLock

详细关于ConcurrentHashMap同步原理 https://www.jianshu.com/p/5dbaa6707017

image.png

重载方法只有参数类型不同,且为父子类,调用选择的时候并不是按照实例类型,而是按照引用类型,强转和经过另一个函数的过滤都会导致在选择进入哪个函数的结果发生变化

扩展:在groovy中,方法的调用是在运行时被选择。这被称为运行时调度和多方法。根据运行时参数类型选择方法。
在java中,这个是相反的,在编译时,根据定义的类型, 选择方法。
以下代码以Java代码的形式编写,可以在Java和Groovy中编译,但其行为会有所不同:

int method(String arg) {
return 1;
}
int method(Object arg) {
return 2;
}
Object o = "Object";
int result = method(o);

在java中 result的值是2,
在groovy中的值是1
java使用的是静态信息类型,o被声明为Object;然而groovy是在运行时选择,这个方法真正被调用的时候。因为o是一个String所以调运String的版本。

  1. volatile 修饰Int 属性变量,能否保证int 属性多线程 自增现成同步呢?
    顺带说下volatile关键字很重要的两个特性:

保证变量在线程间可见,对volatile变量所有的写操作都能立即反应到其他线程中,换句话说,volatile变量在各个线程中是一致的(得益于java内存模型—"先行发生原则");

2、禁止指令的重排序优化;

那么换成volatile修饰count变量后,会有什么效果呢? 试一试:

public class AtomicIntegerTest {

private static final int THREADS_CONUT = 20;
public static volatile int count = 0;

public static void increase() {
    count++;
}

public static void main(String[] args) {
    Thread[] threads = new Thread[THREADS_CONUT];
    for (int i = 0; i < THREADS_CONUT; i++) {
        threads[i] = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    increase();
                }
            }
        });
        threads[i].start();
    }

    while (Thread.activeCount() > 1) {
        Thread.yield();
    }
    System.out.println(count);
}

}
结果似乎又失望了,测试结果和上面的一致,每次都是输出小于20000的数字。这又是为什么么? 上面的论据是正确的,也就是上面标红的内容,但是这个论据并不能得出"基于volatile变量的运算在并发下是安全的"这个结论,因为核心点在于java里的运算(比如自增)并不是原子性的。

你可能感兴趣的:(JAVA小知识点记录(三))