数据同步
数据不一致
在上一篇文章的例子中,我们让四台叫号窗口,叫号1~50,但是运行的时候,可能会出现各种各样的“bug”,包括
- 某个号码被略过 没有出现
- 某个号码重复出现
- 叫号超过50
synchronized
我们可以用synchronized关键词,来简单的、朴素的避免上述情况。它提供一种互斥机制,在同一个时刻,只能有一个线程访问同步资源。
这类似于厕所里的小隔间,一次只能进去一个人,里面的人出来,别人才能够继续进去。
交错使用synchronized来上锁,可能会出现死锁的风险。对于一些开源库,调用层次比较深,可能不能直观地看出来有死锁的风险。例如JDK自带的HashMap,不是线程安全的类,如果在多线程同时写入的情况下,就可能会发生死锁。
如果想用线程安全的map数据结构,可以用ConcurrentHashMap或者Collections.synchronizedMap来代替。
package org.example;
public class Study7Synchronized {
public static void main(String[] args) {
int size = 4;
String[] chineseNums = {"甲", "乙", "丙", "丁"};
SynTicketWindowRunnable runnable = new SynTicketWindowRunnable();
Thread[] threads = new Thread[size];
for (int i = 0; i < size; i++) {
threads[i] = new Thread(runnable, "窗口" + chineseNums[i]);
}
for (int i = 0; i < size; i++) {
threads[i].start();
}
System.out.println("启动各柜台完毕!");
}
}
/**
* 改进之后,不再使用static的index
*/
class SynTicketWindowRunnable implements Runnable {
private static final int MAX = 500;
private int index = 1;
private static final Object MUTEX = new Object();
@Override
public void run() {
while (index <= MAX){
synchronized (MUTEX) {
if (index <= MAX)
System.out.println(Thread.currentThread().getName() + ":" + (index++));
}
}
}
}
如以上代码,我们在涉及修改index
的地方加上了 synchronized
,从而实现了同步。
网友评论