手记

5.3. 线程间通信

线程间通信是指在多个线程之间传递数据和同步它们的执行。Java提供了几种线程间通信的方法,包括:

  1. 使用共享变量
  2. 使用wait()notify()notifyAll()
  3. 使用java.util.concurrent包中的工具类

5.4.1 使用共享变量

线程可以通过访问共享变量实现通信。为了确保线程安全,我们需要对共享变量的访问进行同步。我们可以使用synchronized关键字来实现同步。

示例:两个线程通过共享变量实现通信

class SharedCounter {
    private int counter = 0;

    public synchronized void increment() {
        counter++;
        System.out.println("Counter: " + counter);
    }
}

public class SharedVariableExample {
    public static void main(String[] args) {
        SharedCounter sharedCounter = new SharedCounter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                sharedCounter.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                sharedCounter.increment();
            }
        });

        t1.start();
        t2.start();
    }
}

在上述示例中,我们创建了一个SharedCounter类,它有一个共享变量counter。两个线程通过调用increment()方法来递增计数器。我们使用synchronized关键字确保了对计数器的同步访问。

5.4.2 使用wait()notify()notifyAll()

wait()notify()notifyAll()java.lang.Object类的方法,可以用于在线程间实现通信。这些方法必须在同步代码块或同步方法中使用。

  • wait(): 使当前线程等待,直到其他线程调用此对象的notify()notifyAll()方法。调用wait()时,线程会释放锁,允许其他线程进入同步代码块或同步方法。
  • notify(): 唤醒等待此对象锁的单个线程。如果有多个线程在等待,只有一个线程会被唤醒。
  • notifyAll(): 唤醒等待此对象锁的所有线程。

示例:使用wait()notify()实现生产者-消费者问题

import java.util.LinkedList;
import java.util.Queue;

class ProducerConsumer {
    private Queue<Integer> queue = new LinkedList<>();
    private int maxSize;

    public ProducerConsumer(int maxSize) {
        this.maxSize = maxSize;
    }

    public void produce() throws InterruptedException {
        int value = 0;
        while (true) {
            synchronized (this) {
                while (queue.size() == maxSize) {
                    wait();
                }

                System.out.println("Produced: " + value);
                queue.offer(value++);

                notify();
                Thread.sleep(1000);
            }
        }
    }

    public void consume() throws InterruptedException {
        while (true) {
            synchronized (this) {
                while (queue.isEmpty()) {
                    wait();
                }

                int value = queue.poll();
                System.out.println("Consumed: " + value);

                notify();
                Thread.sleep(1000);
            }
        }
    }
}

public class WaitNotifyExample {
    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer(5);

        Thread producer = new Thread(() -> {
            try {
                pc.produce();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread consumer = new Thread(() -> {
            try {
                pc.consume();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

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

在上述示例中,我们实现了一个生产者-消费者问题。生产者线程和消费者线程通过共享队列进行通信。我们使用wait()notify()方法来同步生产者和消费者的执行。

5.4.3 使用 java.util.concurrent 包中的工具类

java.util.concurrent 包提供了许多工具类,可以用于线程间的通信。这些类包括 SemaphoreCountDownLatchCyclicBarrierExchangerBlockingQueue 等。这些类提供了高级的同步和通信机制,可以简化多线程编程。

下面是使用 BlockingQueue 实现生产者-消费者问题的示例:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

class Producer implements Runnable {
    private final BlockingQueue<Integer> sharedQueue;

    public Producer(BlockingQueue<Integer> sharedQueue) {
        this.sharedQueue = sharedQueue;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                System.out.println("Produced: " + i);
                sharedQueue.put(i);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {
    private final BlockingQueue<Integer> sharedQueue;

    public Consumer(BlockingQueue<Integer> sharedQueue) {
        this.sharedQueue = sharedQueue;
    }

    @Override
    public void run() {
        while (true) {
            try {
                int item = sharedQueue.take();
                System.out.println("Consumed: " + item);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class BlockingQueueExample {
    public static void main(String[] args) {
        BlockingQueue<Integer> sharedQueue = new LinkedBlockingQueue<>();

        Thread producer = new Thread(new Producer(sharedQueue));
        Thread consumer = new Thread(new Consumer(sharedQueue));

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

在这个示例中,我们使用 BlockingQueue 实现生产者-消费者问题。BlockingQueue 是一个线程安全的队列,它提供了阻塞的 put()take() 方法,可以在队列满或空时阻塞生产者或消费者线程。这样,我们不再需要显式地使用 wait()notify() 方法来同步线程。

小结

在本章节中,我们讨论了Java多线程与并发的“5.4 线程间通信”。我们了解了如何使用共享变量、wait()notify()notifyAll()以及java.util.concurrent包中的工具类实现线程间通信。

线程间通信是多线程编程中的关键概念,它可以帮助我们解决复杂的同步和协作问题。掌握这些方法对于编写高效的并发程序至关重要。

请务必多加实践,以便更好地掌握这些知识点。祝你学习顺利!

0人推荐
随时随地看视频
慕课网APP