元婴期
15. Java 中的同步(synchronization)机制是什么?如何使用 synchronized
关键字?
同步机制 是 Java
中用于解决并发问题的关键手段。多线程访问共享资源时,可能会导致数据不一致。
synchronized
关键字用于确保同一时间只有一个线程可以访问共享资源。
实例方法同步:整个方法被锁定,同一时间只能有一个线程执行该方法。
代码块同步:锁定某个对象,用于更细粒度的同步控制。
class Counter {
private int count = 0;
// 同步方法
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SynchronizationExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
// 创建多个线程同时访问共享资源
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + counter.getCount());
}
}
synchronized
确保同一时间只有一个线程可以访问 increment()
方法,避免竞争条件。
16. 什么是 wait()
、notify()
和 notifyAll()
?它们在线程通信中的作用是什么?
wait()
、notify()
和 notifyAll()
是 Java
中的线程通信机制,常用于同步块内的线程协调:
wait()
:使当前线程进入等待状态,释放锁,直到其他线程调用 notify()
或 notifyAll()
。
notify()
:唤醒一个正在等待的线程。
notifyAll()
:唤醒所有等待的线程。
class Message {
private String msg;
public Message(String str) {
this.msg = str;
}
public String getMsg() {
return msg;
}
public void setMsg(String str) {
this.msg = str;
}
}
class Waiter implements Runnable {
private Message msg;
public Waiter(Message m) {
this.msg = m;
}
public void run() {
synchronized (msg) {
try {
System.out.println("Waiting for message...");
msg.wait(); // 线程进入等待状态
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Received message: " + msg.getMsg());
}
}
}
class Notifier implements Runnable {
private Message msg;
public Notifier(Message m) {
this.msg = m;
}
public void run() {
synchronized (msg) {
msg.setMsg("Notification complete");
msg.notify(); // 唤醒等待的线程
}
}
}
public class WaitNotifyExample {
public static void main(String[] args) throws InterruptedException {
Message msg = new Message("Process it");
Thread waiter = new Thread(new Waiter(msg));
Thread notifier = new Thread(new Notifier(msg));
waiter.start();
Thread.sleep(1000);
notifier.start();
}
}
wait()
让线程进入等待状态,notify()
唤醒等待的线程,notifyAll()
则唤醒所有等待的线程。
17. 什么是线程池(Thread Pool)?如何使用 ExecutorService
管理线程?
线程池 是一种优化多线程管理的方式,减少频繁创建和销毁线程的开销。
ExecutorService
提供了创建和管理线程池的机制。
Fixed Thread Pool:指定固定大小的线程池。
Cached Thread Pool:根据需要动态创建线程。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
final int taskID = i;
executor.submit(() -> {
System.out.println("Task " + taskID + " is running");
});
}
executor.shutdown(); // 关闭线程池
}
}
ExecutorService
管理一组线程,避免频繁创建销毁。shutdown()
用于在任务完成后关闭线程池。
18. 什么是 Lambda 表达式?Java 中如何使用 Lambda 表达式?
Lambda 表达式 是 Java 8
引入的一个简洁的匿名函数表达式,用于实现函数式接口。Lambda 表达式使得代码更简洁,特别是对于匿名内部类的使用。
- 语法:
(parameters) -> expression
或(parameters) -> {statements}
import java.util.Arrays;
import java.util.List;
public class LambdaExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用 Lambda 表达式遍历列表
names.forEach(name -> System.out.println(name));
// 使用 Lambda 实现 Runnable
new Thread(() -> System.out.println("Lambda thread running")).start();
}
}
Lambda
表达式使代码更加简洁和可读,特别适用于简单的操作,例如遍历集合或实现 Runnable
接口。
19. Java 中的 final
关键字有什么作用?可以用在哪些地方?
final
关键字用于限制修改,主要有以下几种用法:
变量:声明为 final
的变量只能赋值一次,之后不能修改。
方法:声明为 final
的方法不能在子类中重写。
类:声明为 final
的类不能被继承。
// final 变量
public class FinalExample {
public static void main(String[] args) {
final int MAX_VALUE = 100;
// MAX_VALUE = 200; // 错误:不能修改 final 变量
System.out.println(MAX_VALUE);
}
}
// final 类
final class Car {
public void run() {
System.out.println("Car is running");
}
}
// final 方法
class Vehicle {
public final void start() {
System.out.println("Vehicle started");
}
}
20. 什么是 Java 的自动装箱(Autoboxing)和拆箱(Unboxing)?它们如何工作?
自动装箱 是 Java
自动将基本数据类型转换为其对应的包装类,例如 int
转换为 Integer
。
拆箱 则是 Java
自动将包装类转换为基本数据类型,例如 Integer
转换为 int
。
public class BoxingExample {
public static void main(String[] args) {
// 自动装箱
Integer intObj = 100; // 自动将 int 转换为 Integer
// 拆箱
int intValue = intObj; // 自动将 Integer 转换为 int
System.out.println("Integer: " + intObj);
System.out.println("int: " + intValue);
}
}
装箱和拆箱使得基本类型与包装类型之间的转换更加简单和自动化。
21. 什么是 Java 的内存模型(Memory Model)?如何管理对象的生命周期和垃圾回收?
Java
内存模型(Java Memory Model, JMM
)定义了线程如何通过共享变量进行交互和如何保证可见性。
它规定了:
堆内存:存储对象和实例变量,由所有线程共享。
栈内存:存储局部变量和方法调用,每个线程拥有自己的栈。
Java
的垃圾回收(Garbage Collection, GC) 自动管理对象的生命周期,释放不再使用的对象所占用的内存,避免内存泄漏。垃圾回收通常使用标记-清除算法来实现。
public class GarbageCollectionExample {
public static void main(String[] args) {
GarbageCollectionExample obj = new GarbageCollectionExample();
obj = null; // 使对象不可达
// 手动请求垃圾回收
System.gc();
System.out.println("Garbage collection requested");
}
@Override
protected void finalize() throws Throwable {
System.out.println("Garbage collected");
}
}
System.gc()
请求垃圾回收,finalize()
方法在对象被回收时调用(不建议依赖 finalize()
进行资源管理)。