在 Java 中,线程同步和线程协作是两个非常重要的概念,它们有助于解决多线程环境中出现的竞争条件和线程间的协调问题。
1. 线程同步
线程同步是指当多个线程共享某些资源时,通过某些机制(如锁)来保证某些代码块在同一时刻只能被一个线程执行,从而避免线程之间的冲突。
常见的同步方式:
- synchronized关键字:用于修饰方法或代码块,保证同一时刻只有一个线程能够执行该方法或代码块。
- ReentrantLock:Java 提供的另一种同步机制,允许更细粒度的锁控制。
示例代码:使用 synchronized
来进行线程同步
public class Counter {
private int count = 0;
// 使用 synchronized 确保线程安全
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
}
public class ThreadSyncExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
// 创建多个线程来操作 Counter 对象
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
thread1.start();
thread2.start();
// 等待两个线程执行完毕
thread1.join();
thread2.join();
System.out.println("Final count: " + counter.getCount());
}
}
在这个示例中,increment
和 decrement
方法使用了 synchronized
关键字,确保了同一时刻只有一个线程可以访问这些方法,避免了竞争条件,保证了线程安全。
2. 线程协作
线程协作是指不同线程之间通过某些机制进行相互配合,完成一些任务。例如,一个线程可以等待其他线程的完成,或者多个线程可以协调执行某些任务。
常见的协作方式:
- wait() 和 notify() / notifyAll():这是最常见的线程协作机制。一个线程可以调用
wait()
方法等待,直到另一个线程调用notify()
或notifyAll()
唤醒它。 - CountDownLatch:一个线程可以等待其他线程完成某些任务后再继续执行。
- CyclicBarrier:允许一组线程互相等待,直到所有线程都到达某个屏障点。
示例代码:使用 wait()
和 notify()
来进行线程协作
public class SharedResource {
private int counter = 0;
// 生产者方法
public synchronized void produce() throws InterruptedException {
while (counter >= 1) {
wait(); // 如果资源已满,等待消费者消费
}
counter++;
System.out.println("Produced, counter: " + counter);
notify(); // 唤醒消费者线程
}
// 消费者方法
public synchronized void consume() throws InterruptedException {
while (counter <= 0) {
wait(); // 如果没有资源,等待生产者生产
}
counter--;
System.out.println("Consumed, counter: " + counter);
notify(); // 唤醒生产者线程
}
}
public class ThreadCooperationExample {
public static void main(String[] args) throws InterruptedException {
SharedResource resource = new SharedResource();
// 创建生产者线程
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
resource.produce();
Thread.sleep(500); // 模拟生产时间
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 创建消费者线程
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
resource.consume();
Thread.sleep(1000); // 模拟消费时间
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
}
}
在这个示例中,SharedResource
类充当一个共享资源,生产者线程通过 produce()
方法生产资源,消费者线程通过 consume()
方法消费资源。两个线程使用 wait()
和 notify()
进行协作:
- 当生产者生产时,如果资源已经满了,它会调用
wait()
等待消费者消费。 - 当消费者消费时,如果没有资源,它会调用
wait()
等待生产者生产。
通过这种方式,生产者和消费者能够有效地协作,保证不会发生竞争条件。
总结
- 线程同步:通过保证共享资源的互斥访问来避免竞争条件,常用的方式包括
synchronized
和ReentrantLock
。 - 线程协作:通过线程间的协作机制来实现线程间的协调,常见的机制包括
wait()
/notify()
和CountDownLatch
。
同步用于解决数据共享时的冲突问题,而协作则解决多个线程间的协调问题。