java八股文

java八股文

浅拷贝和深拷贝

浅拷贝:只拷贝基本类型;
深拷贝:会拷贝所有类型数据(包括引用类型)

浅拷贝实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.cslb.day1;

public class Address implements Cloneable{ //1. 实现Cloneable接口
private String city;
private int no;

//省略了构造函数和getter setter toString

// 2. 覆盖 clone() 方法实现浅拷贝
@Override
public Address clone() throws CloneNotSupportedException {
return (Address)super.clone();
}

}

浅拷贝和引用拷贝的测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DeepClone {
public static void main(String[] args) throws CloneNotSupportedException {
Address a1 = new Address("bj",1);
Address a2 = a1; //两个不同的引用指向同一个对象
Address a3 = a1.clone(); //浅拷贝(只拷贝了基本类型)

a2.setNo(2);
a3.setCity("sh");

System.out.println(a1); //Address{city='bj', no=2}
System.out.println(a2); //Address{city='bj', no=2}
System.out.println(a3); //Address{city='sh', no=1}

}
}

一张图来描述浅拷贝、深拷贝、引用拷贝:
alt text

深拷贝的实现:(深拷贝对象里的引用类型对象也要实现Cloneable接口)

1
2
3
4
5
6
7
@Override
public Person clone() throws CloneNotSupportedException{
Person person = (Person) super.clone();
person.setAddress(person.getAddress().clone()); //对象里的引用类型也要进行一个单独的拷贝(String除外)
return person;
}

线程安全和线程不安全的集合

线程安全集合

  • Vector
  • HahTable
  • Collections.synchronizedXXX包装后的集合类
  • ConcurrentHashMap
  • CopyOnWriteArrayList
  • CopyOnWriteArraySet

实现原理:

  1. Vector/HashTable

方法上加synchronized(对象锁)

  1. Collections.synchronizedXXX包装后的集合类
    以Collections.synchronizedList为例,它返回的是一 SynchronizedRandomAccessList(如果原始列表是RandomAccess类型)或SynchronizedList(如果原始列表不 RandomAccess类型)。这些包装类内部维护了一个原始的集合对象,并通过在所有方法上添加synchronized块来实现同步
1
2
List<Integer> list = new ArrayList<>();
List<Integer> synchronizedList = Collections.synchronizedList(list);
  1. ConcurrentHashMap
    ConcurrentHashMap 采用了分段锁(Segment)的机制来实现高效的并发访问。它将整个哈希表分成多个段(Segment),每个段都类似于一个独立的HashTable,有自己的锁。例如,当一个线程对某一个段中的数据进行操作时,只会锁住这个段,其他段的数据仍然可以被其他线程访问和操作。这样就大大减少了锁的竞争,提高了并发性能

在对节点进行操作(如插入或更新元素)时会获取节点对应的锁(这里的f是一个节点对象),这样可以精确地控制并发访问,避免对整个哈希表进行全局锁定。

  1. CopyOnWriteArrayList 和 CopyOnWriteArraySet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}

首先获取锁(ReentrantLock),然后复制原数组,将新元素添加到新数组中,最后将新数组赋值给内部的数组引用,完成添加操作后释放锁。

这种写时复制的方式保证了在修改操作进行时,不会影响正在进行的读取操作。因为读取操作是在原数组上进行的,而修改操作是在新的副本数组上进行的,所以读取操作不需要加锁,在高并发的读取场景下性能较好。

不过,由于每次修改都需要复制数组,会消耗额外的内存和时间,所以这种集合适合在读取操作频繁而修改操作相对较少的场景下使用。

线程不安全集合

  • ArrayList
  • LinkedList
  • HashSet
  • TreeSet
  • HashMap
  • TreeMap

java八股文
https://cs-lb.github.io/2024/11/15/Java/java八股文/
作者
Liu Bo
发布于
2024年11月15日
许可协议