实现runnable接口需共用同一实例才能共享对象,应将共享数据封装为独立线程安全管理器,仅对关键操作加锁,避免锁整个run方法,并区分无需共享的局部变量。

实现 Runnable 接口本身不自动共享对象,但它是实现对象共享最自然、最常用的方式——关键在于“共用一个实例”和“合理组织共享数据”。只要设计得当,比继承 Thread 更灵活、更安全。
用同一个 Runnable 实例启动多个线程
这是共享的前提。只有多个 Thread 构造时传入的是**同一个 Runnable 对象**,它们才真正操作同一份成员变量。
- ✅ 正确:先 new 一个 MyTask(),再用它创建 Thread(t), Thread(t), Thread(t)
- ❌ 错误:new Thread(new MyTask()), new Thread(new MyTask()) —— 每个线程都有独立副本,根本没共享
把共享数据抽离成独立管理器
别让 Runnable 类既管逻辑又管状态。把可变共享资源(如票数、计数器、队列)封装成单独的类,比如 TicketPool 或 CounterManager。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 这个管理器内部用 AtomicInteger、ConcurrentHashMap 等线程安全类型
- 提供 tryTake()、increment() 等带业务语义的方法,隐藏同步细节
- Runnable 实现类只调用这些方法,不直接读写字段
同步粒度要准,别锁整个 run()
共享状态被多线程并发修改时,必须加保护,但不必锁住全部逻辑。
- 避免 synchronized(run) {} —— 整个 run 方法被串行化,失去并发意义
- 推荐 synchronized(this) { if (pool.hasTicket()) pool.sell(); } —— 只锁关键判断+变更段
- 更优:用 ReentrantLock 或原子类(如 pool.getRemaining().decrementAndGet())替代手写 synchronized
分清哪些本就不该共享
不是所有东西都要“共享”,很多变量天然线程安全,强行加锁反而画蛇添足。
- 方法内声明的变量(如 for(int i=0; i
- String、Integer、BigDecimal 等不可变对象,即使多个线程引用同一个实例,也不会被修改
- static 字段虽能共享,但易引发全局耦合,优先考虑封装在管理器中
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










