本文共 1838 字,大约阅读时间需要 6 分钟。
我们都知道多线程效率高,在我们学习集合的时候就知道,ArrayList线程不安全,效率高。那么线程不安全到底是怎么样的回事呢。我们来看看这个案例:
/** * 经典案例,多个线程卖票:用来展示多线程不安全问题 */public class ThreadSellTickets implements Runnable{ //定义初始票数 private int ticket = 100; //定义循环终止标记 boolean flag = true; @Override public void run() { //循环卖票 while (flag) { buyTicket(); } } private void buyTicket() { //判断票数是否小于等于零,如果是,将flag的值改为false,跳出循环,说明没票了 if (ticket<=0){ flag=false; //没票了就跳出方法 return; } //模拟网络延时,让线程睡100ms。扩大出现错误的可能性。这里出现异常,捕获处理 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("run方法里出现了异常"); } System.out.println(Thread.currentThread().getName()+"买到了第"+ticket+"张票"); //每次循环票数减一 ticket--; } //主线程 public static void main(String[] args) { //获取ThreadSellTickets对象 ThreadSellTickets sellTickets = new ThreadSellTickets(); //创建多个线程,去抢票(多个线程处理同一资源);并给线程起名字 new Thread(sellTickets,"张三黄牛").start(); new Thread(sellTickets,"李四黄牛").start(); new Thread(sellTickets,"王五黄牛").start(); }}
输出结果:
通过输出结果我们发现,出现了很多相同票的,还有0票的。那么为什么会出现两个人都买到了同一张票或者都已经没有票了还能买到票呢。这就牵扯线程安全问题了。为什么能两个线程都拿到同一张票呢?
是因为当两个线程同时进入卖票方法里面是,它们互相并不知道还有别的线程也进来了,所以他们两个都拿着同一个编号的票走了,计算机并不像我们人这么聪明,所以才会出现线程不安全。那又是为什么会拿到0票呢?甚至负票呢。
加入票就剩下最后一张了,然后张三和李四都进入买票方法里了,然后张三和李四也都经过判断知道票数还不小于0,然后往下走,李四却快一步,将最后一张票拿走。那么票数就成了0,然后张三又不知道票数是0,就又将票数减一,拿走了一张,这就导致出现了线程不安全。处理方法,简单了解
那么我们如何处理线程不安全呢,这里简单提一下,是不是我们每次只让一个人进入方法里,就可以避免拿同一张票或者拿到负票呢?当然是可以的,Java给我们提供了一个关键字synchronized是可以将代码块或者方法锁住,一次只让一个线程通过,所以就可以使线程安全,但是效率当然会变慢。为什么所ArrayList线程不安全但是效率快呢,就是因为它底层的实现源码没有用synchronized修饰,线程不安全,自然效率快。转载地址:http://waiwi.baihongyu.com/