这是一个测试

问题:问题输入,这是一个摘要的的测试,后面的内容在首页是看不见的

阅读全文

currentHashMap详解

CurrentHashMap对比HashMap而言是一个线程安全的map,和HashTable不同的是,线程安全实现的方法不同,同时效率更高。

Map 特点
HashMap 底层是数组+(链表|红黑树)的数据结构,是线程不安全的,key中可以存储null
HashTable 底层实现和HashMap一样,但是是线程安全的,通过使用sychronized对get,add方法进行了同步,但是锁的粒度太大,效率较低,key,value中不可以存储null
CurrentHashMap 底层也是hash的,同时也是线程安全的,效率比HashTable更高,大量使用了volatile,final,CAS等技术来减少锁竞争对于性能的损失。同时1.7和1.8的实现方法有点不同

CurrentHashMap在jdk1.7中的实现原理

数组+Segment+分段锁实现的

image-20201004215651077

其中会有两次hash的过程,第一次hash用来找到对应的segment,第二次hash找到元素所在链表的头部

该结构所带来的的

好处是:只用对Segment加锁,这样相对于对整个hashMap的get,add方法加锁,提高了性能

坏处是:对比普通的HashMap需要两次hash的过程

CurrentHashMap在jdk1.8中的实现

CurrentHashMap在jdk1.8的实现参考了HashMap在1.8中的底层实现,使用了数组+链表,红黑树的数据结构来实现,同时用了CAS操作(Compare and swap)。

CAS:即比较交换,是乐观锁。(在java中有分为乐观锁和悲观锁,注意悲观锁和乐观锁的定义)性能比较乐观锁性能较悲观锁更高。

CAS中主要包含三个操作数:内存位置V,预期原值A和新值B,如果内存地址里面的值和A是一样的,那么就将内存里面的值更新成B,

多线程排序

问题:问题输入

*思路: 思路输入

1
// 代码输入位置

ArrayList详解

本文将结合java源码详细介绍ArrayList的底层实现:

​ 首先ArrayList的底层是一个Object类型的数组,当执行new ArrayList()的时候,数组的长度是0,当对象调用add()函数的时候,会创建一个初始长度为10的数组。在ArrayList里面有两个构造函数,无参的构造函数会创建一个默认长度为10的数组,当使用有参的构造函数时,若传入的参数大于0,则创建一个对应参数大小的数组,若等于0则创建一个默认长度10的数组,否则报出一个IlleglArgumentException的异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private static final int DEFAULT_CAPACITY = 10;

/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}

public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

当调用add函数的时候,源代码如下。不要索引的add函数会直接将元素加在当前arrayList对象的末尾,会首先使用ensureCapacityInternal函数,会判断此时的ArrayList对象是否需要进行扩容,会比较当前的容量和minCapacity的值,minCapacity代表的是当前对象加入了当前元素个数,当加入之前的数组为空时,则minCapacity记为起始默认的数组长度10,否则记为加入之前对象中元素的个数加一。

若此时的minCapacity大于当前数组的长度是,则使用grow()函数对数组进行扩容,然后对扩容后的数组给size++索引位置赋值给添加元素,否者直接对size++出的直接赋值即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,size - index);
elementData[index] = element;
size++;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}

private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private void ensureExplicitCapacity(int minCapacity) {
modCount++;

// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

此时的grow函数才是真正地对ArrayList对象进行扩容,若当前的minCapacity大于当前数组长度的1.5则需要新的数组需要扩容到之前的1.5倍,否则需要新数组长度等于minCapacity长度大小。(什么情况下会发生呢?)同时在grow函数里面还需要和ArrayList可以的最大size(MAX_ARRAY_SiZE)比较,如果此时的minCapacity小于零会报OOM错误,否则会将更新的长度赋值为Integer.MAX_VLUE长度。然后使用Arrays里面的copyOf进行复制数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void grow(int minCapacity) {
// overflow-conscious code 这是为了防止int溢出所作的处理
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
}

Arrays里面的copyOf函数会重新创建一个数组长度为参数的数组,将原来数组里面的元素按照原来的位置一次存入新的数组。

同步和异步的关系

1.同步和异步定义

同步:调用某个资源时,调用放需要的等待这个调用返回结果才能继续往后面执行。
异步:与同步相反,在调用发出后,调用者可以继续执行后面的操作,被调用者通过状态通知调用者,或者通过回调函数来通知结果。

image-20200902161347854

image-20200902161426341

2.同步异步和阻塞非阻塞的关系:

同步异步和阻塞非阻塞是两个不同的概念

同步和异步:强调的是消息通信机制。

阻塞和非阻塞:强调的是程序在等待调用结果(消息,返回值)时的状态。阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前的线程。对于同步调用来说。很多时候当前线程还处于激活的状态,只是从逻辑上当前函数没有返回而已,即同步等待时什么都不干,白白占用资源。

3.线程同步和线程通信

4.进程同步和进程通信

*思路: 思路输入

1
// 代码输入位置

java实现单链表

*思路: 思路输入

1
2
3
4
// 代码输入位置



找出缺失的一个数

问题: 给出一个长度为n-1的int类型的数组,里面的数组是1到n里面的n-1数,且没有重复的数组,请找出其中缺失的那一个数字,

思路: 使用异或运算来求解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 代码输入位置
public class Main{

public static void main(String[] args){
// 输入的n-1个长度的数组
int[] arr = {1,2,3,6,7,8};
int n = arr.length+1;

int re = 0;
for(int i =0;i<n-1;i++){
re ^= arr[i];
re ^= (i+1);
}
re ^= (n);
System.out.println("缺失的数字是"+re);
}
}

最大子序列和

问题:求取给给出的一个数值中,元素中的数值有正有负,最大的子数组和是多少?

*思路: 思路输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 代码输入位置
public class Main {
public static void method(int[] arr){
/**
* 方法1:使用暴力的方法
* */
int sum = 0,max = 0;
// 子序列开始的索引下标位置
for (int i = 0; i < arr.length; i++) {
sum = arr[i];
// 从i开始的子序列,长度依次增加
for (int j = i+1; j < arr.length; j++) {
sum += arr[j];
max = Math. max(max,sum);
}
}
System.out.println(max);
}

public static void method2(int[] arr){

}


public static void main(String[] args) {
int[] arr = new int[]{1,3,1,12,-12,12,-1,3,5,-1,8,2,-5,-5,9};
method(arr);

}
}



$ \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt,. $
$$\Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt,.$$

$$x=a_0 + \cfrac {1^2}{a_1 + \cfrac {2^2}{a_2 + \cfrac {3^2}{a_3 + \cfrac {4^2}{a_4 + …}}}}$$

最大平均子序列

问题:输入一个长度为n的数组a,求数组中最大的平均子序列

思路: 使用滑动窗口思想,右指针不断地向数组尾部移动,元素大小不断增大就继续移动,知道元素大小小于前一个位置的元素大小停止移动;然后对左指针进行移动

1
2
3
4
5
6
7
8
9
// 代码输入位置
public class Main{

public static void main(String[] args){

}

}