一 什么是共享资源
共享资源指的是多个线程同时对同一份资源进行访问(读写操作),被多个线程访问的资源就是共享资源,如何保证多个线程访问到的数据是一致的,则被称为数据同步或者资源同步。
二 数据不一致问题的引入
先看一段代码,它模拟的是营业厅叫号程序。
package concurrent;
public class TicketWindowRunnable implements Runnable {
private int index = 1;
private final static int MAX = 500;
@Override
public void run() {
while (index <= MAX) {
System.out.println(Thread.currentThread() + "的号码是:" + (index++));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final TicketWindowRunnable task = new TicketWindowRunnable();
Thread windowThread1 = new Thread(task, "1号窗口");
Thread windowThread2 = new Thread(task, "2号窗口");
Thread windowThread3 = new Thread(task, "3号窗口");
Thread windowThread4 = new Thread(task, "4号窗口");
windowThread1.start();
windowThread2.start();
windowThread3.start();
windowThread4.start();
}
}
多次运行上面这段代码,会发现出现了三种问题。
-
某个号码被略过没有出现
-
某个号码多次显示
-
号码超过了最大值500
三 数据不一致问题分析
1 号码被略过
线程的执行是由 CPU 时间片轮询调度的,假设此时线程1和线程2都执行到 index =65,其中线程2将 index 修改为 66 之后未输出之前,CPU 调度器将执行权利交给线程1,线程1将其累加到67,那么66就忽略了。
2 号码重复出现
线程1执行 index+1,然后CPU执行权落入线程2手里,由于线程1并没有给index赋予计算后的结果393,因此线程2执行index+1的结果仍然是393,所以会出现重复号码的情况
3 号码超过了最大值
当 index =499 的时候,线程1和线程都满足条件,线程2短暂停留,线程1强index增加到500,线程2恢复运行后又将500增加到501,此时出现了超过最大值的情况。