案例一:自动售票机
package com.UnSafeDemo;
public class sellTickets extends Thread{
@Override
public void run() {
sell();
}
private int tickets = 3;
public static void main(String[] args) {
sellTickets machine = new sellTickets();
new Thread(machine,"张三").start();
new Thread(machine,"李四").start();
new Thread(machine,"黄牛党").start();
}
void sell()
{
while (this.tickets>0)
{
System.out.println(Thread.currentThread().getName()+"买走了第"+tickets+"张票");
tickets--;
}
}
}
我们让三个买票的线程张三、李四、黄牛党同时在售票机前买票。票的数量用tickets来存储。出现了以下异常的数据
由于票具有唯一性,同一张票不可能卖给不同的人。所以程序存在线程不安全的情况。
案例二:ArrayList线程不安全案例
package com.UnSafeDemo;
import java.util.ArrayList;
public class ArrayListDemo {
public static void main(String[] args) throws InterruptedException {
ArrayList list = new ArrayList();
for (int i = 0; i < 100000; i++) {
new Thread(
()->{
list.add(Thread.currentThread().getName());
}
).start();
}
Thread.sleep(3000);
System.out.println(list.size());
}
}
以上案例我们声明了一个ArrayList的对象,在10000次的for循环中,我们每次都声明一个线程,线程的run方法用lamda表达式重写,方法体为每次向ArrayList中添加当前线程的名字。
最后我们让主线程休眠3秒以等待循环的结束,最后输出List的长度。
在我们脑海中,由于执行了10000次循环体,所以List长度应该为10000
然而真实的List的长度却并没有达到10000
这是由于ArrayList是线程不安全的,不同的变量i所对应的循环体内的操作可能操作了同一线程所导致的安全隐患。