Appearance
Java 线程同步
在Java中,Thread
类和Runnable
接口是实现多线程的主要方式。当多个线程同时访问共享资源时,可能会导致数据不一致或程序崩溃。为了控制线程的执行顺序并确保共享资源的安全访问,我们需要使用线程同步机制。
1. 使用 synchronized
关键字
synchronized
是一个关键字,用于定义方法或者代码块为 synchronized 块。它保证了在同一时间只有一个线程可以执行这个块或方法。
示例:用 synchronized
同步两个线程的输出
java
public class SynchronizationExample {
public static void main(String[] args) {
Runnable task = () -> {
for (int i = 0; i < 10; i++) {
synchronized (this) { // 使用 this 关键字作为锁对象
System.out.println(Thread.currentThread().getName() + " - " + i);
}
}
};
Thread thread1 = new Thread(task, "Thread-1");
Thread thread2 = new Thread(task, "Thread-2");
thread1.start();
thread2.start();
// 确保线程完成
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2. 使用 ReentrantLock
类
ReentrantLock
是一个可重入锁,它允许同一个线程多次获取同一把锁。与synchronized
相比,它可以提供更灵活的锁定策略。
示例:用 ReentrantLock
实现同步
java
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
public static void main(String[] args) {
final Lock lock = new ReentrantLock();
Runnable task = () -> {
for (int i = 0; i < 10; i++) {
lock.lock(); // 获取锁
try {
System.out.println(Thread.currentThread().getName() + " - " + i);
} finally {
lock.unlock(); // 解锁
}
}
};
Thread thread1 = new Thread(task, "Thread-1");
Thread thread2 = new Thread(task, "Thread-2");
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3. 避免死锁
死锁是指两个或多个线程无限期地等待对方释放资源的情况。为了避免死锁,可以采取以下措施:
- 避免嵌套锁定:尽量不要让一个线程在获取一个锁的同时又去请求另一个锁。
- 使用超时机制:在获取锁的时候设置超时时间,这样如果无法获得锁,则自动释放。
示例:用 ReentrantLock
设置等待超时
java
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockWithTimeoutExample {
public static void main(String[] args) {
final Lock lock = new ReentrantLock();
Runnable task = () -> {
for (int i = 0; i < 10; i++) {
try {
boolean acquired = lock.tryLock(1, TimeUnit.SECONDS);
if (!acquired) { // 如果无法获得锁,则继续循环
System.out.println(Thread.currentThread().getName() + " - 等待锁超时");
continue;
}
System.out.println(Thread.currentThread().getName() + " - 正在运行:" + i);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
};
Thread thread1 = new Thread(task, "Thread-1");
Thread thread2 = new Thread(task, "Thread-2");
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4. 总结
synchronized
:关键字,用于同步方法或代码块。ReentrantLock
:类,提供可重入锁机制,更灵活的锁定策略。- 死锁:避免嵌套锁定和使用超时机制。