51. Java中的WeakHashMap是什么?它与HashMap有什么不同?
-
WeakHashMap:
WeakHashMap
是一种特殊的HashMap
,其键是弱引用,即当键对象没有被其他对象强引用时,可以被垃圾回收器回收。- 主要用于特定场景下需要动态管理对象映射关系的情况。
-
与HashMap的不同:
HashMap
的键是强引用,只有在显式移除键值对或清空整个HashMap
时,键才会被释放。WeakHashMap
的键可以被自动回收,适合用于缓存等需要动态管理内存的场景。
52. Java中的CopyOnWriteArrayList是什么?它的特性和适用场景是什么?
-
CopyOnWriteArrayList:
CopyOnWriteArrayList
是并发容器之一,用于替代ArrayList
在并发环境下的操作。- 写操作(添加、修改)会复制一份底层数组,因此写操作开销较大,但读操作非常高效且线程安全。
-
特性和适用场景:
- 线程安全:适用于读多写少的场景,如事件监听器列表。
- 迭代安全:支持并发迭代而不需要额外的同步。
- 实时更新:适合于实时数据访问和更新的场景,如实时统计数据的读取。
53. Java中的HashMap如何处理哈希冲突?有哪些解决冲突的方法?
- 哈希冲突处理:
- 链地址法(Separate Chaining):即在同一哈希桶位置使用链表或其他数据结构存储冲突的键值对。
- 开放地址法(Open Addressing):
- 线性探测法:发生冲突时,依次查找下一个可用位置。
- 二次探测法:冲突时,根据某种二次方程探测下一个位置。
- 再哈希法:使用另一个哈希函数计算下一个位置。
54. Java中的ConcurrentHashMap是如何实现线程安全的?
- 实现线程安全:
- 使用分段锁(Segment Locking):
ConcurrentHashMap
内部分成多个段(Segment),每个段拥有自己的锁。 - 锁分离:不同段的锁互不影响,从而提高并发性能。
- 读操作可以并发进行,写操作只锁定对应的段,避免了整个数据结构的锁。
- 使用分段锁(Segment Locking):
55. Java中的ThreadLocal有什么使用场景?它如何保证线程安全?
-
使用场景:
- 保存线程私有的上下文信息,如数据库连接、会话信息等。
- 避免传递参数的麻烦,每个线程都能够独立访问保存在
ThreadLocal
中的数据。
-
线程安全保证:
- 每个线程访问
ThreadLocal
时,实际访问的是线程自己的变量副本,因此不存在线程安全问题。 - 但需要注意的是,
ThreadLocal
中保存的数据对于多个线程是不共享的,每个线程修改不会影响其他线程的数据。
- 每个线程访问
56. Java中的Volatile关键字是如何保证可见性的?
- 可见性保证:
Volatile
关键字修饰的变量会被存储在主内存中,而不是线程的工作内存中。- 每次访问
volatile
变量时,都会从主内存中读取最新的值,修改后也会立即写回主内存。 - 因此,对
volatile
变量的修改对其他线程可见,保证了可见性。
57. Java中的CAS(Compare and Swap)操作是什么?它在哪些并发框架中应用广泛?
-
CAS操作:
- CAS是一种乐观锁技术,通过比较当前值和期望值是否一致来决定是否更新变量的值。
compareAndSet
是CAS操作的典型表现,通常应用于原子类(如AtomicInteger
、AtomicReference
等)的实现中。
-
应用广泛的并发框架:
- Java中的
Atomic
包:提供了基于CAS操作的原子类。 - 各种并发容器和并发工具类中,如
ConcurrentHashMap
、CountDownLatch
等,都广泛使用CAS来实现线程安全操作。
- Java中的
58. Java中的Thread类和Runnable接口有什么区别?它们如何实现线程?
-
区别:
Thread
类是线程的实现类,直接继承Thread
类并重写run()
方法可以创建线程。Runnable
接口是线程任务的定义,实现Runnable
接口的类需要作为参数传递给Thread
类的构造方法中。
-
线程实现:
- 继承
Thread
类:直接创建Thread
的子类,重写run()
方法。 - 实现
Runnable
接口:创建一个实现了Runnable
接口的类,在Thread
类的构造方法中传入该对象。
- 继承
59. Java中的Semaphore是什么?它的主要作用和使用场景是什么?
-
Semaphore:
Semaphore
是一个计数信号量,用于控制同时访问某个特定资源的线程数量。- 可以用来限制同时访问的线程数量,或者用于实现资源池的分配管理。
-
主要作用和使用场景:
- 限流:控制某些资源同时访问的线程数,比如数据库连接池。
- 并发访问控制:保护共享资源,例如文件、数据库等。
- 多任务并行处理:控制并发线程的数量,以避免资源耗尽或性能下降。
110. Java中的ReentrantLock和synchronized关键字有什么区别?它们在什么情况下应该使用?
-
区别:
- ReentrantLock:
- 是显式锁,需要手动获取和释放锁。
- 支持公平锁和非公平锁。
- 提供了更灵活的锁获取和释放机制,可以实现更复杂的同步结构。
- synchronized关键字:
- 是隐式锁,由Java虚拟机自动管理,无需手动获取和释放。
- 只支持非公平锁。
- 使用简单,代码量少,适合简单的同步场景。
- ReentrantLock:
-
使用情况:
- ReentrantLock:需要更灵活的锁定方式,例如尝试获取锁定、超时获取锁、公平锁等场景。
- synchronized关键字:简单的同步代码块或方法,性能要求不高且不需要额外的功能时。