Java并发编程札记-(一)基础-05线程安全问题
来源:互联网 发布:海森伯格矩阵图片 编辑:程序博客网 时间:2024/06/06 03:14
在多线程编程中,可能会出现多个线程访问一个资源的情况,资源可以是同一内存区(变量,数组,或对象)、系统(数据库,web services等)或文件等等。如果不对这样的访问做控制,就可能出现不可预知的结果。这就是线程安全问题,常见的情况是“丢失修改”、“不可重复读”、“读‘脏’数据”等等。
目录
- 线程安全问题
- 线程安全的实现
线程安全问题
上面简单介绍了什么是线程安全问题,下面具体说下什么是“丢失修改”,其他的问题有兴趣可以自己去了解。
丢失修改
两个事务T1和T2读入同一数据并修改,T2提交的结果破坏了T1提交的结果,导致T1的修改被丢失。
拿火车票订票系统举例:
- 一号窗口读出某班次的火车票余票A,设A=1;
- 二号窗口读出同一班次的火车票余票B,当然也为1;
- 一号窗口判断出余票A=1>0,卖出一张火车票,修改余票A←A-1,A为0,把A写回数据库;
- 二号窗口判断出余票B=1>0,也卖出一张火车票,修改余票B←B-1,B为-1;
余票只有一张,但最后卖出了两张火车票。在程序中,没有对两个窗口对余票的访问做控制,所以造成了这个错误。
例1:火车票订票系统-线程不安全版
public class SellTickets { public static void main(String[] args) { TicketsWindow tw = new TicketsWindow(); Thread t1 = new Thread(tw, "一号窗口"); Thread t2 = new Thread(tw, "二号窗口"); t1.start(); t2.start(); }}class TicketsWindow implements Runnable { private int tickets = 1; @Override public void run() { while (true) { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "还剩余票:" + tickets + "张"); tickets--; System.out.println(Thread.currentThread().getName() + "卖出一张火车票,还剩" + tickets + "张"); } else { System.out.println(Thread.currentThread().getName() + "余票不足,暂停出售!"); try { Thread.sleep(1000 * 60 * 5); } catch (InterruptedException e) { e.printStackTrace(); } } } }}
运行结果为
一号窗口还剩余票:1张二号窗口还剩余票:1张一号窗口卖出一张火车票,还剩0张二号窗口卖出一张火车票,还剩-1张一号窗口余票不足,暂停出售!二号窗口余票不足,暂停出售!
这明显不是我们想要的结果。
线程安全问题解决方法
上面的问题归根结底是由于两个线程访问相同的资源造成的。对于并发编程,需要采取措施防止两个线程来访问相同的资源。
一种措施是当资源被一个线程访问时,为其加锁。第一个访问资源的线程必须锁定该资源,是其他任务在资源被解锁前不能访问该资源。
基本上所有的并发模式在解决线程安全问题时,都采用“序列化访问临界资源”的方案。即在同一时刻,只能有一个线程访问临界资源,也称作同步互斥访问。通常来说,是在访问临界资源的代码前面加上一个锁,当访问完临界资源后释放锁,让其他线程继续访问。
在Java多线程编程当中,提供了以下几种方式来实现线程安全:
- 内部锁(Synchronized)和显式锁(Lock)。这两种方式是重量级的多线程同步机制,可能会引起上下文切换和线程调度,它同时提供内存可见性、有序性和原子性。
- volatile:轻量级多线程同步机制,不会引起上下文切换和线程调度。仅提供内存可见性、有序性保证,不提供原子性。
- CAS原子指令:轻量级多线程同步机制,不会引起上下文切换和线程调度。它同时提供内存可见性、有序性和原子化更新保证。
本文就讲到这里,想了解更多内容请参考:
- Java并发编程札记-目录
END.
阅读全文
1 0
- Java并发编程札记-(一)基础-05线程安全问题
- Java并发编程札记-(一)基础-02创建线程
- Java并发编程札记-(一)基础-03线程的生命周期
- Java并发编程---线程安全问题
- Java并发编程札记-(一)基础-01基本概念
- Java并发编程札记-(一)基础-04Thread详解
- Java并发编程札记-(一)基础-06synchronized详解
- Java并发编程札记-(一)基础-07volatile详解
- java并发编程之线程同步基础(一)
- java并发编程(一基本概念、线程基础)
- java线程编程安全问题
- Java并发编程札记-目录
- Java 并发编程 基础 一
- 【Java并发编程】一.基础
- Java并发基础(一)-线程基础
- Java基础之线程安全问题
- 《java并发编程》读书笔记--线程基础
- java并发编程基础之线程安全
- Git rebase 和git merge 使用技巧20171119
- 模拟实现strcpy ,strstr,strcat,strcmp,memcpy,memmove
- Netty学习笔记(二) Channel和ChannelFuture
- SpringBoot事务管理
- JavaShowAlgorithm-使用2个栈实现队列
- Java并发编程札记-(一)基础-05线程安全问题
- 中介者模式
- 安卓VectorDrawable矢量图在原图基础上添加点击时 ripple 水波纹特效
- random随机数
- Eclipse插件springsource-tool-suite的下载和安装
- C语言_可变参数列表解析
- java基础(三)
- LeetCode:Best Time to Buy and Sell Stock with Cooldown
- android 视图 sufaceview