Java面试必备:线程与进程、多线程同步、内存管理深度解析

需积分: 0 0 下载量 7 浏览量 更新于2024-08-04 收藏 9KB MD 举报
"Java面试题,涵盖进程与线程的区别、TreeMap的定义、线程停止、多线程编程最佳实践、Java编码方案及其特点、唤醒阻塞线程的方法、内存区域的解释以及多线程同步策略和自旋锁的概念。" ### 1. 进程与线程的区别 **进程**是一个在内存中运行的应用程序,每个程序运行时都会成为一个独立的进程,拥有自己的资源,如代码、数据和系统资源。**线程**是进程内部的执行单元,它共享进程的资源,拥有独立的程序计数器、栈和局部变量。进程间的资源是独立的,而线程间可以共享数据。进程切换代价较高,线程切换则相对较低。 ### 2. TreeMap的定义 TreeMap是Java集合框架中的一种有序映射(Map)实现,它基于红黑树数据结构。TreeMap保证了插入的键值对按照其键的自然顺序(或提供的比较器)进行排序。这使得TreeMap可以提供有序的遍历,同时支持高效的查找、插入和删除操作。 ### 3. 如何停止一个正在运行的线程 在Java中,无法直接停止一个线程。通常建议通过设置标志位来通知线程停止工作,然后在线程的run()方法中检查这个标志位,当标志位为true时,线程会自行结束。使用`Thread.interrupt()`可以中断线程,但并不保证线程会立即停止,需要在代码中处理InterruptedException。 ### 4. 多线程编程的最佳实践 - 使用`ExecutorService`管理线程池,避免线程创建和销毁的开销。 - 尽量避免长时间阻塞操作,如I/O操作。 - 合理使用同步机制,如`synchronized`关键字、`ReentrantLock`等,防止竞态条件。 - 使用原子类(`java.util.concurrent.atomic`包)减少锁的使用。 - 避免死锁、活锁和饥饿现象。 - 实现`Runnable`接口而不是继承`Thread`类,除非需要直接继承其他类。 ### 5. Java语言编码方案及特点 Java语言默认采用UTF-8编码方案,它是Unicode字符集的一个变体,具有广泛的字符支持,能够处理多种语言的字符。UTF-8的特点包括: - 变长编码,节省空间,对英文字符效率高。 - 兼容ASCII码。 - 不同长度的字节序列代表不同的字符,有助于错误检测。 ### 6. 唤醒一个阻塞的线程 在Java中,可以使用`Object`类的`notify()`或`notifyAll()`方法唤醒等待在该对象监视器上的线程。但需要注意,被唤醒的线程并不会立即执行,而是进入就绪状态,等待CPU的下一个调度。 ### 7. 内存中的栈、堆和方法区的用法 - **栈**:用于存储基本类型和对象引用,以及方法调用时的局部变量。栈内存的分配和释放非常快,但大小有限。 - **堆**:存放所有实例对象和数组。堆内存的大小可动态扩展,并且线程间共享。 - **方法区**(在Java 8之后被元空间取代):存储类信息、常量、静态变量和编译后的代码。同样为所有线程共享。 ### 8. 多线程同步方法 - `synchronized` 关键字:用于方法或代码块,确保同一时间只有一个线程执行特定代码。 - `Lock` 接口和实现类(如`ReentrantLock`):提供了比`synchronized`更细粒度的锁控制。 - `volatile` 关键字:确保多线程环境下的可见性和有序性,但不保证原子性。 - `wait()`, `notify()` 和 `notifyAll()`:用于对象级别的同步,线程通过这些方法等待或唤醒其他线程。 - `CyclicBarrier` 和 `Semaphore`:提供同步和计数器功能,用于协调多个线程的执行。 ### 9. 自旋锁 自旋锁是一种非阻塞的同步机制。当线程尝试获取一个被其他线程占用的锁时,自旋锁会让线程循环等待(即“自旋”),直到锁变为可用状态。自旋锁适用于持有锁的时间很短的情况,因为它避免了线程上下文切换的开销,但如果持有锁的时间较长,自旋会消耗大量CPU资源。在Java中,`java.util.concurrent.locks.LockSupport.parkNanos()` 和 `LockSupport.unpark(Thread)` 可用于实现自旋锁。