本篇是为了同步问题的引出。
实际上所谓的同步指的就是多个线程访问同一资源所引出的问题。
范例:观察非同步情况下的操作(多人卖票问题)
package TestDemo;
class MyThread implements Runnable{//Runnable接口子类,也是线程公有对象,其实例化对象在堆中
private int ticket=5;
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(this.ticket>0)
System.out.println(Thread.currentThread().getName()+",sell ticket="+this.ticket--);
}
}
}
public class TestDemo{
public static void main(String[] args)throws Exception{
MyThread mt=new MyThread();
new Thread(mt,"seller A").start();
new Thread(mt,"seller B").start();
new Thread(mt,"seller C").start();
new Thread(mt,"seller D").start();
}
}
image.png
此时没有问题出现是因为在一个JVM进程下运行,并且没有受到任何影响,如果要想观察到问题,可以加入一个延迟。
package TestDemo;
class MyThread implements Runnable{//Runnable接口子类,也是线程公有对象,其实例化对象在堆中
private int ticket=5;
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(this.ticket>0){
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+",sell ticket="+this.ticket--);
}
}
}
}
public class TestDemo{
public static void main(String[] args)throws Exception{
MyThread mt=new MyThread();
new Thread(mt,"seller A").start();
new Thread(mt,"seller B").start();
new Thread(mt,"seller C").start();
new Thread(mt,"seller D").start();
}
}
发现出现了脏数据。
image.png
不仅出现了重复数据,还出现了负数,这就是不同步的状况,整个卖票的步骤分为两步:
第一步:判断是否还有剩余的票数
第二步:减少剩余票数
image.png
我们可以将中间的休眠想象成高并发下的程序运行,压力增大情况下,如果不对票数进行同步加锁,就会出现脏数据,设想一下,12306抢票的时候,高并发情况下,票数需要加锁,否则就会出现票数为负的情况,或者同一张票卖给了两人,是灾难性的。因而线程安全的核心思想:"要么只读,要么加锁。"
网友评论