Java高频面试之并发编程-11

hello啊,各位观众姥爷们!!!本baby今天又来报道了!哈哈哈哈哈嗝🐶

面试官:父子线程如何共享数据?

在Java中,父子线程共享数据可以通过以下几种方式实现,具体选择取决于应用场景和需求:


1. 通过共享对象成员变量

父线程和子线程共享同一个对象的成员变量,需使用同步机制确保线程安全。

java 复制代码
class SharedData {
    private int value;
    public synchronized void setValue(int value) { this.value = value; }
    public synchronized int getValue() { return value; }
}

public class Main {
    public static void main(String[] args) {
        SharedData data = new SharedData();
        data.setValue(100);

        Thread childThread = new Thread(() -> {
            System.out.println("子线程读取数据: " + data.getValue()); // 输出 100
        });
        childThread.start();
    }
}

注意事项

  • 使用 synchronizedLock 确保原子性。
  • 使用 volatile 保证可见性(适用于简单变量的读写)。

2. 通过构造器参数传递初始数据

父线程在创建子线程时,通过构造器或 Runnable 传递数据。

java 复制代码
class ChildThread implements Runnable {
    private final String message;
    public ChildThread(String message) {
        this.message = message;
    }
    @Override
    public void run() {
        System.out.println("子线程接收消息: " + message);
    }
}

public class Main {
    public static void main(String[] args) {
        String message = "Hello from parent";
        Thread childThread = new Thread(new ChildThread(message));
        childThread.start();
    }
}

适用场景:初始化时传递数据,后续无动态更新。


3. 使用线程安全的数据结构

通过 ConcurrentHashMapBlockingQueue 等并发容器共享数据。

java 复制代码
import java.util.concurrent.ConcurrentHashMap;

public class Main {
    private static ConcurrentHashMap<String, String> sharedMap = new ConcurrentHashMap<>();

    public static void main(String[] args) {
        sharedMap.put("key", "初始值");

        Thread childThread = new Thread(() -> {
            sharedMap.put("key", "子线程修改后的值");
        });
        childThread.start();

        try {
            childThread.join(); // 等待子线程结束
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("父线程读取数据: " + sharedMap.get("key")); // 输出 "子线程修改后的值"
    }
}

优点:无需显式同步,高并发性能好。


4. 使用 InheritableThreadLocal

子线程继承父线程的线程局部变量(适用于传递初始化值)。

java 复制代码
public class Main {
    private static InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();

    public static void main(String[] args) {
        inheritableThreadLocal.set("父线程设置的值");

        Thread childThread = new Thread(() -> {
            System.out.println("子线程读取数据: " + inheritableThreadLocal.get()); // 输出 "父线程设置的值"
        });
        childThread.start();
    }
}

限制 :子线程创建后,父线程对 InheritableThreadLocal 的修改不会影响子线程。


5. 使用 FutureCallable

父线程通过 Future 获取子线程的执行结果。

java 复制代码
import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(() -> {
            return 42; // 子线程计算结果
        });

        int result = future.get(); // 父线程阻塞等待结果
        System.out.println("父线程获取结果: " + result); // 输出 42
        executor.shutdown();
    }
}

适用场景:需要异步获取子线程执行结果。


6. 使用回调(Callback)机制

子线程完成任务后通过回调接口通知父线程。

java 复制代码
interface Callback {
    void onComplete(String result);
}

class ChildThread implements Runnable {
    private final Callback callback;
    public ChildThread(Callback callback) {
        this.callback = callback;
    }
    @Override
    public void run() {
        String result = "处理完成";
        callback.onComplete(result);
    }
}

public class Main {
    public static void main(String[] args) {
        new Thread(new ChildThread(result -> {
            System.out.println("父线程接收回调结果: " + result); // 输出 "处理完成"
        })).start();
    }
}

总结与选型建议

方式 适用场景 线程安全要求 灵活性
共享对象成员变量 简单数据共享,需频繁更新 高(需同步)
构造器参数传递 初始化时传递数据 低(仅初始化)
线程安全数据结构 高并发环境下的数据共享 低(容器内部已处理)
InheritableThreadLocal 传递线程局部初始化值 低(仅初始化)
Future/Callable 异步获取子线程结果 无(结果单向传递)
回调机制 异步通知父线程 低(回调方法需线程安全)

注意事项

  • 可见性与原子性 :共享变量需使用 volatile 或同步机制确保可见性,复合操作需保证原子性。
  • 资源释放 :使用线程池时,确保及时关闭并清理资源(如 ExecutorService.shutdown())。
  • 避免死锁:合理设计锁的获取顺序,避免嵌套锁竞争。
相关推荐
蜡笔小马6 分钟前
10.Boost.Geometry R-tree 空间索引详解
开发语言·c++·算法·r-tree
IOsetting6 分钟前
金山云主机添加开机路由
运维·服务器·开发语言·网络·php
kali-Myon7 分钟前
2025春秋杯网络安全联赛冬季赛-day1
java·sql·安全·web安全·ai·php·web
我是咸鱼不闲呀10 分钟前
力扣Hot100系列20(Java)——[动态规划]总结(下)( 单词拆分,最大递增子序列,乘积最大子数组 ,分割等和子集,最长有效括号)
java·leetcode·动态规划
清水白石00820 分钟前
深入解析 LRU 缓存:从 `@lru_cache` 到手动实现的完整指南
java·python·spring·缓存
林开落L20 分钟前
从零开始学习Protobuf(C++实战版)
开发语言·c++·学习·protobuffer·结构化数据序列化机制
牛奔25 分钟前
Go 是如何做抢占式调度的?
开发语言·后端·golang
符哥200833 分钟前
C++ 进阶知识点整理
java·开发语言·jvm
小猪咪piggy33 分钟前
【Python】(4) 列表和元组
开发语言·python
不想秃头的程序员44 分钟前
Vue3 封装 Axios 实战:从基础到生产级,新手也能秒上手
前端·javascript·面试