高级java每日一道面试题-2024年7月27日-并发篇-Java如何先多线程之间的通讯和协作?

面试官: Java如何先多线程之间的通讯和协作?

我回答:

Java中多线程之间的通信和协作

多线程通信和协作是指在多线程环境下,多个线程通过特定的方式进行信息交换或者协调它们的执行顺序,从而确保程序的正确性和高效性。Java提供了多种机制来支持线程间的通信和协作,包括但不限于同步、共享变量、等待/通知机制、线程间通信工具类等。

1. 使用synchronized关键字

synchronized关键字是最基本的同步机制之一,它可以用于同步方法或同步代码块,以确保同一时刻只有一个线程可以访问被同步的方法或代码块。

示例
public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

2. 使用wait()notify() / notifyAll()

wait()notify() / notifyAll() 方法可以用于线程之间的等待和通知机制。这些方法必须在synchronized代码块或方法中调用。

示例
public class SimpleProducerConsumer {
    private final Object lock = new Object();
    private int value = 0;

    public void produce() throws InterruptedException {
        synchronized (lock) {
            while (value != 0) {
                lock.wait(); // 等待
            }
            value = 1; // 生产
            System.out.println("Produced: " + value);
            lock.notify(); // 通知
        }
    }

    public void consume() throws InterruptedException {
        synchronized (lock) {
            while (value == 0) {
                lock.wait(); // 等待
            }
            value = 0; // 消费
            System.out.println("Consumed: " + value);
            lock.notify(); // 通知
        }
    }
}

3. 使用volatile关键字

volatile关键字用于声明一个变量在多线程环境中可以被多个线程共享访问,并且修改后的值会立刻对所有线程可见。

示例
public class VolatileExample {
    private volatile boolean running = true;

    public void start() {
        new Thread(() -> {
            while (running) {
                // 执行任务
            }
            System.out.println("Thread stopped.");
        }).start();
    }

    public void stop() {
        running = false;
    }
}

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

Java并发包java.util.concurrent提供了许多高级工具类来帮助实现线程间的通信和协作,比如ExecutorServiceCountDownLatchCyclicBarrierSemaphoreExchanger等。

示例: CountDownLatch
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    private static final int NUM_THREADS = 5;
    private static final CountDownLatch latch = new CountDownLatch(NUM_THREADS);

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < NUM_THREADS; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " is running.");
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " finished.");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

        latch.await(); // 等待所有线程完成
        System.out.println("All threads have finished.");
    }
}

5. 使用BlockingQueueConcurrentHashMap

BlockingQueue提供了一种线程安全的方式来实现生产者-消费者模式,而ConcurrentHashMap提供了线程安全的键值对存储。

示例: BlockingQueue
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class BlockingQueueExample {
    private static final BlockingQueue<String> queue = new LinkedBlockingQueue<>(10);

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            try {
                while (true) {
                    String item = queue.take();
                    System.out.println("Consumed: " + item);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();

        for (int i = 0; i < 10; i++) {
            queue.put("Item " + i);
            System.out.println("Produced: Item " + i);
        }
    }
}

6. 使用FutureCallable

FutureCallable可以用于异步执行任务并获取结果。

示例: FutureCallable
import java.util.concurrent.*;

public class FutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(() -> {
            Thread.sleep(1000);
            return 42;
        });

        System.out.println("Result: " + future.get());
        executor.shutdown();
    }
}

7. 使用CompletableFuture

CompletableFuture提供了更高级的异步编程模型,支持组合和流式处理。

示例: CompletableFuture
import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return 42;
        }).thenApply(i -> i * 2);

        future.thenAccept(System.out::println);
    }
}

8. 使用LockCondition

Java的java.util.concurrent.locks包中的Lock接口和Condition接口提供了比传统synchronized方法和语句更灵活的线程同步和协作机制。

  • Lock:是一个接口,提供了比synchronized更广泛的锁定操作。它允许更灵活的结构,可以具有完全不同的属性,并且可以支持多个相关的Condition对象。
  • Condition:是Lock对象中用来实现线程之间的协作,包括等待/通知机制。一个Lock对象可以创建多个Condition实例,这些Condition实例分别管理那些处于等待状态的线程。
示例: LockCondition
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockAndConditionExample {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private int value = 0;

    public void produce() throws InterruptedException {
        lock.lock();
        try {
            while (value != 0) {
                condition.await(); // 等待
            }
            value = 1; // 生产
            System.out.println("Produced: " + value);
            condition.signal(); // 通知
        } finally {
            lock.unlock();
        }
    }

    public void consume() throws InterruptedException {
        lock.lock();
        try {
            while (value == 0) {
                condition.await(); // 等待
            }
            value = 0; // 消费
            System.out.println("Consumed: " + value);
            condition.signal(); // 通知
        } finally {
            lock.unlock();
        }
    }
}

注意事项

  • 在使用wait()notify()notifyAll()方法时,需要确保它们被包裹在同步代码块或同步方法中,并且当前线程必须拥有对象的锁。
  • LockCondition提供了更灵活的线程同步和协作机制,但也需要谨慎使用,以避免死锁等问题。
  • 并发工具类如CountDownLatchCyclicBarrierSemaphore等简化了多线程编程的复杂性,但在使用时也需要理解其内部机制,以选择最合适的工具。

总结来说,在Java中实现线程间的通信和协作有很多方法可以选择,根据具体的场景和需求来选择最适合的技术方案。在实际开发中,合理地运用这些机制能够极大地提高程序的并发性能和稳定性。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java我跟你拼了

您的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值