Java 线程互斥的概念和实现
在多线程编程中,线程互斥是一种用于确保多个线程访问共享资源时的同步技术。这种技术可以防止多个线程同时对共享资源进行修改或访问,从而避免数据不一致和意外结果的产生。在 Java 中,线程互斥可以通过锁机制来实现。
锁是一种同步机制,它可以确保某个被标记为锁定的代码块在同一时刻只能被一个线程执行。Java 提供了内置的锁对象,例如 synchronized 关键字和 Lock 接口的实现类,可以用于实现线程互斥。
使用 synchronized 关键字可以将代码块声明为同步代码块,从而确保只有一个线程可以执行该代码块。当线程进入同步代码块时,它会尝试获取该代码块的锁,如果锁已经被其他线程获取,那么线程就会进入等待状态。直到锁被释放,线程才能继续执行。以下是一个使用 synchronized 实现线程互斥的示例:
public class MutexExample {
private static int counter = 0;
private static final Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
for (int i = 0; i < 10000; i++) {
counter++;
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
for (int i = 0; i < 10000; i++) {
counter++;
}
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Counter: " + counter);
}
}
在上面的示例中,我们创建了两个线程,它们共享一个静态计数器 counter。通过 synchronized 关键字,我们确保每一次对 counter 进行加操作时只有一个线程可以访问。最后,我们打印出 counter 的值,观察是否得到期望的结果。
除了 synchronized 关键字之外,Java 还提供了 Lock 接口及其实现类,例如 ReentrantLock。这种锁机制需要手动地获取和释放锁,相比 synchronized 关键字更加灵活。使用 Lock 接口的代码示例如下:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MutexExample {
private static int counter = 0;
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
lock.lock();
try {
for (int i = 0; i < 10000; i++) {
counter++;
}
} finally {
lock.unlock();
}
});
Thread thread2 = new Thread(() -> {
lock.lock();
try {
for (int i = 0; i < 10000; i++) {
counter++;
}
} finally {
lock.unlock();
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Counter: " + counter);
}
}
在这个示例中,我们使用了 ReentrantLock 类来实现互斥锁。通过调用 lock() 方法获取锁,然后在 try-finally 块中执行代码块,最后使用 unlock() 方法释放锁。这种方式更加灵活,可以满足一些复杂的同步需求。
总结来说,Java 线程互斥是一种用于确保多个线程访问共享资源时的同步技术。通过使用锁机制,例如 synchronized 关键字和 Lock 接口的实现类,我们可以实现线程互斥,避免数据不一致和意外结果的产生。