线程同步是指在多个线程之间协调和控制访问共享资源的机制。当多个线程同时访问共享资源时,可能会导致数据不一致或冲突的问题。为了避免这些问题,我们需要使用线程同步来确保每个线程按照特定的顺序访问共享资源。
常见的线程同步机制有互斥锁(Mutex)、信号量(Semaphore)和条件变量(Condition Variable)等。
互斥锁是最基本的线程同步机制,它通过给共享资源加锁来防止其他线程访问该资源,从而实现线程安全。只有获得锁的线程才能执行临界区代码,其他线程则需要等待锁释放后才能进行访问。
信号量是一种更高级的线程同步机制,它可以用来限制对共享资源的访问数量。通过设置一个计数器,线程可以根据信号量的值来判断是否可以继续执行或者需要等待。
条件变量用于在线程之间传递信息,它通常与互斥锁配合使用。当某个线程发出特定条件满足的信号时,其他等待该条件的线程将被唤醒并开始执行。
在Java中,可以使用synchronized关键字和对象的wait()、notify()、notifyAll()方法来实现线程同步和条件变量的功能。synchronized关键字可以用于修饰方法或代码块,确保在同一时间只有一个线程执行被修饰的代码。
以下是一个简单的Java示例,演示了如何使用synchronized关键字和wait()、notify()方法进行线程同步和条件变量的使用:
class SharedResource {
private boolean isReady = false;
public synchronized void produce() {
while (isReady) { // 等待资源可用
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产资源
System.out.println("Producing resource...");
isReady = true;
notify(); // 唤醒等待的消费者线程
}
public synchronized void consume() {
while (!isReady) { // 等待资源可用
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 消费资源
System.out.println("Consuming resource...");
isReady = false;
notify(); // 唤醒等待的生产者线程
}
}
public class Main {
public static void main(String[] args) {
SharedResource sharedResource = new SharedResource();
Thread producerThread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
sharedResource.produce();
}
});
Thread consumerThread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
sharedResource.consume();
}
});
producerThread.start();
consumerThread.start();
try {
producerThread.join();
consumerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上面的示例中,SharedResource类表示一个共享资源,其中produce()方法用于生产资源,consume()方法用于消费资源。使用synchronized关键字修饰这两个方法,确保每次只有一个线程可以执行它们。
在主函数中,创建了一个生产者线程和一个消费者线程,并分别启动它们。通过调用join()方法等待这两个线程执行完毕。
当生产者线程生产资源时,如果资源已经准备好,则调用wait()方法使当前线程进入等待状态,直到消费者线程消费资源并唤醒生产者线程。同样地,当消费者线程消费资源时,如果资源不可用,则调用wait()方法使当前线程进入等待状态,直到生产者线程生产资源并唤醒消费者线程。
请注意,在使用wait()、notify()或notifyAll()方法时,必须先获取对象的锁(即在synchronized代码块或synchronized方法中调用),否则会抛出IllegalMonitorStateException异常。