Java之线程篇三:线程的同步与通讯

在多线程编程中,线程的同步与通讯是确保线程安全和良好协作的关键东西。本篇文章将介绍Java中线程同步的基本概念、常用的同步工具、以及线程之间的通讯机制。

线程同步的基本概念

在多线程环境下,多个线程可能会同时访问共享资源,如变量、对象等。这可能导致数据的不一致性或状态错误。例如,两个线程同时对一个变量进行写操作,如果没有正确的同步措施,最终结果可能会出错。因此,线程同步就是为了避免以上情况的发生。

常用的同步机制

Java提供了多种机制来实现线程同步,最常用的包括:synchronized关键字、Lock接口以及ReentrantLock类。

1. 使用synchronized关键字

synchronized关键字可以修饰方法或代码块,确保同一时刻只有一个线程可以访问被修饰的代码。

class Counter {
    private int count = 0;

    // 使用synchronized修饰方法
    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class SyncExample {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new 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("Counter: " + counter.getCount());
    }
}

在上述例子中,increment方法被synchronized修饰,因此当一个线程在执行这个方法时,其他线程将无法同时访问该方法,从而确保了count变量的线程安全。

2. 使用Lock接口

ReentrantLock是Java提供的一种更灵活的线程同步机制,可以替代synchronized关键字。它提供了比synchronized更高级的功能,例如可中断的锁、定时锁等。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class CounterLock {
    private int count = 0;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock(); // 上锁
        try {
            count++;
        } finally {
            lock.unlock(); // 解锁
        }
    }

    public int getCount() {
        return count;
    }
}

public class LockExample {
    public static void main(String[] args) throws InterruptedException {
        CounterLock counter = new CounterLock();

        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("Counter: " + counter.getCount());
    }
}

在这个例子中,我们使用ReentrantLock来实现线程安全。通过lock和unlock方法手动控制锁的获取与释放,这种方式更灵活,也能避免死锁的发生。

线程通讯

线程通讯通常是指一个线程影响另一个线程的执行,最常用的方式是使用wait()notify()notifyAll()方法,它们都是在对象的监视器上进行操作。

下面是一个简单的生产者-消费者示例:

class SharedResource {
    private int count;
    private final int LIMIT = 10;

    public synchronized void produce() throws InterruptedException {
        while (count == LIMIT) {
            wait(); // 等待
        }
        count++;
        System.out.println("Produced: " + count);
        notifyAll(); // 通知消费者
    }

    public synchronized void consume() throws InterruptedException {
        while (count == 0) {
            wait(); // 等待
        }
        count--;
        System.out.println("Consumed: " + count);
        notifyAll(); // 通知生产者
    }
}

public class ProducerConsumerExample {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();

        Runnable producer = () -> {
            for (int i = 0; i < 20; i++) {
                try {
                    resource.produce();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        };

        Runnable consumer = () -> {
            for (int i = 0; i < 20; i++) {
                try {
                    resource.consume();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        };

        new Thread(producer).start();
        new Thread(consumer).start();
    }
}

在这个示例中,我们创建了一个SharedResource类,其中包含了生产和消费的逻辑。使用wait()notifyAll()实现了生产者和消费者间的通讯。当缓冲区满时,生产者会等待;当缓冲区为空时,消费者会等待。

总结

Java的线程同步与通讯是多线程编程中非常重要的组成部分。通过合理使用synchronized、Lock以及wait/notify机制,可以有效地实现线程间的协作与资源的安全访问。随着对多线程编程理解的加深,开发者能够更加自如地应对各种复杂的同步场景。

点赞(0) 打赏

微信小程序

微信扫一扫体验

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部