MST

星途 面试题库

面试题:Java命令模式在多线程环境下的应用及挑战

讨论在多线程环境中使用Java命令模式可能面临的挑战,例如线程安全、资源竞争等问题。阐述如何对传统的Java命令模式进行改进以适应多线程环境,给出详细的设计思路和关键代码示例。
15.6万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

多线程环境下Java命令模式面临的挑战

  1. 线程安全问题:在多线程环境中,如果多个线程同时访问和执行同一个命令对象,可能会导致数据不一致。例如,命令对象内部维护了一些状态变量,不同线程对这些变量的操作顺序和时机不同,就可能引发错误。
  2. 资源竞争:当多个命令需要访问共享资源(如文件、数据库连接等)时,会出现资源竞争问题。如果没有适当的同步机制,可能导致数据损坏或程序异常。

改进设计思路

  1. 使用线程安全的数据结构:在命令对象中,如果需要维护状态,使用线程安全的数据结构,如ConcurrentHashMapCopyOnWriteArrayList等。
  2. 同步机制:对共享资源的访问使用synchronized关键字或者Lock接口进行同步控制,确保同一时间只有一个线程可以访问共享资源。
  3. 命令队列与线程池:将命令放入队列中,使用线程池来处理队列中的命令,这样可以控制并发度,避免过多线程同时执行命令导致资源耗尽。

关键代码示例

  1. 定义命令接口
public interface Command {
    void execute();
}
  1. 具体命令类
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConcreteCommand implements Command {
    private static int sharedResource = 0;
    private static Lock lock = new ReentrantLock();

    @Override
    public void execute() {
        lock.lock();
        try {
            // 访问和修改共享资源
            sharedResource++;
            System.out.println("Command executed, sharedResource: " + sharedResource);
        } finally {
            lock.unlock();
        }
    }
}
  1. 调用者(Invoker)
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Invoker {
    private BlockingQueue<Command> commandQueue;
    private ThreadPoolExecutor executor;

    public Invoker(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {
        commandQueue = new LinkedBlockingQueue<>();
        executor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                commandQueue);
    }

    public void addCommand(Command command) {
        commandQueue.add(command);
    }

    public void start() {
        executor.prestartAllCoreThreads();
    }

    public void stop() {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
                if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                    System.err.println("Pool did not terminate");
                }
            }
        } catch (InterruptedException ie) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}
  1. 测试代码
public class Main {
    public static void main(String[] args) {
        Invoker invoker = new Invoker(2, 4, 10, TimeUnit.SECONDS);
        for (int i = 0; i < 10; i++) {
            invoker.addCommand(new ConcreteCommand());
        }
        invoker.start();
        invoker.stop();
    }
}

在上述代码中,ConcreteCommand类通过Lock接口保证了对共享资源sharedResource的线程安全访问。Invoker类使用ThreadPoolExecutorBlockingQueue来管理命令的执行,控制并发度,从而适应多线程环境。