如果通过 Runnable 接口实现多线程,则多线程实现类中的属性可被多个线程共享。当多个线程同时操作线程同一个共享资源时,有大概率出现资源同步问题,导致最终的结果偏离我们预期的最终结果,甚至完全相反。
下面通过一个简单实例,演示一下多线程的资源同步问题,示例源代码如下所示:
package com.fanfengping.demo; import lombok.extern.slf4j.Slf4j; @Slf4j public class Demo14RunnableSync implements Runnable { private int stockTicket = 50; private int saleTicket = 0; @Override public void run() { while (stockTicket > 0) { log.info("{} 出票一张,售出票数:{},剩余票数:{}", Thread.currentThread().getName(), ++saleTicket, --stockTicket); } } public static void main(String[] args) { Demo14RunnableSync demo14RunnableSync = new Demo14RunnableSync(); for (int i = 1; i < 5; i++) { new Thread(demo14RunnableSync, "窗口" + i).start(); } } }
执行程序,输出的结果如下所示:
[窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:3,剩余票数:47 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:1,剩余票数:49 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:5,剩余票数:45 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:6,剩余票数:44 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:7,剩余票数:43 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:8,剩余票数:42 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:9,剩余票数:41 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:4,剩余票数:46 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:10,剩余票数:40 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:2,剩余票数:48 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:11,剩余票数:39 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:12,剩余票数:38 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:14,剩余票数:36 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:16,剩余票数:34 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:13,剩余票数:37 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:17,剩余票数:33 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:18,剩余票数:32 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:19,剩余票数:31 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:15,剩余票数:35 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:21,剩余票数:29 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:20,剩余票数:30 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:23,剩余票数:27 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:24,剩余票数:26 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:22,剩余票数:28 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:25,剩余票数:25 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:26,剩余票数:24 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:27,剩余票数:23 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:29,剩余票数:21 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:30,剩余票数:20 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:25,剩余票数:25 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:28,剩余票数:22 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:31,剩余票数:19 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:34,剩余票数:16 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:32,剩余票数:18 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:35,剩余票数:15 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:36,剩余票数:14 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:37,剩余票数:13 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:39,剩余票数:11 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:33,剩余票数:17 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:40,剩余票数:10 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:38,剩余票数:12 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:41,剩余票数:9 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:42,剩余票数:8 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:43,剩余票数:7 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:44,剩余票数:6 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:45,剩余票数:5 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:46,剩余票数:4 [窗口2] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口2 出票一张,售出票数:48,剩余票数:2 [窗口1] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口1 出票一张,售出票数:47,剩余票数:3 [窗口3] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口3 出票一张,售出票数:50,剩余票数:0 [窗口4] INFO com.fanfengping.demo.Demo14RunnableSync - 窗口4 出票一张,售出票数:49,剩余票数:1
由此可见,多线程操作无保护同一线程资源时,会导致预期偏离。
那么,如何解决多线程资源同步问题呢? Java 中可通过同步代码块(synchronized)实现,具体示例请参阅后续文章。