JAVA线程安全机制
来源:互联网 发布:郝海东网络直播视频 编辑:程序博客网 时间:2024/05/19 00:53
前言
在进行java线程安全机制讲解之前,先谈谈java线程和java内存模型的基础知识。
一、线程与内存交互操作
所有的变量(实例字段,静态字段,构成数组对象的元素,不包括局部变量和方法参数)都存储在主内存中,每个线程有自己的工作内存,线程的工作内存保存被线程使用到变量的主内存副本拷贝。线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存的变量。不同线程之间也不能直接访问对方工作内存中的变量,线程间变量值的传递通过主内存来完成。
Java内存模型定义了八种操作:
- lock(锁定):作用于主内存的变量,它把一个变量标识为一个线程独占的状态;
- unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定;
- read(读取):作用于主内存的变量,它把一个变量的值从主内存传送到线程中的工作内存,以便随后的load动作使用;
- load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中;
- use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎;
- assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存中的变量;
- store(存储):作用于工作内存的变量,它把工作内存中的一个变量的值传送到主内存中,以便随后的write操作;
- write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值写入主内存的变量中。
2)禁止指令重排序优化。
注:volatile关键字不能保证在多线程环境下对共享数据的操作的正确性。可以使用在自己状态改变之后需要立即通知所有线程的情况下。
1. 为什么需要多线程(多线程的优势)
2. 多线程带来的问题—线程安全
3. 产生线程不安全的原因
4. 有哪些方法能解决线程不安全
------系好安全带-------
一:为什么需要多线程?
线程是Java语言中不可或缺的重要部分,它们能使复杂的异步代码变得简单,简化复杂系统的开发;能充分发挥多处理器系统的强大计算能力。
(1) 优点
1. 充分利用硬件资源。由于线程是cpu的基本调度单位,所以如果是单线程,那么最多只能同时在一个处理器上运行,意味着其他的CPU资源都将被浪费。而多线程可以同时在多个处理器上运行,只要各个线程间的通信设计正确,那么多线程将能充分利用处理器的资源。
2. 结构优雅。多线程程序能将代码量巨大,复杂的程序分成一个个简单的功能模块,每块实现复杂程序的一部分单一功能,这将会使得程序的建模,测试更加方便,结构更加清晰,更加优雅。
3. 简化异步处理。为了避免阻塞,单线程应用程序必须使用非阻塞I/O,这样的I/O复杂性远远高于同步I/O,并且容易出错。
(2) 缺点
1. 线程安全:由于统一进程下的多个线程是共享同样的地址空间和数据的,又由于线程执行顺序的不可预知性,一个线程可能会修改其他线程正在使用的变量,这一方面是给数据共享带来了便利;另一方面,如果处理不当,会产生脏读,幻读等问题,好在Java提供了一系列的同步机制来帮助解决这一问题,例如内置锁。
2. 活跃性问题。可能会发生长时间的等待锁,甚至是死锁。
3. 性能问题。 线程的频繁调度切换会浪费资源,同步机制会导致内存缓冲区的数据无效,以及增加同步流量。
二:线程安全
(1) 定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替运行,并且在主调试代码中不需要任何额外的同步或者协同,这个类都能表现出正确的行为,则称这个类时线程安全的。线程安全类中封装了必要的同步机制,因此客户端无须进一步采取同步措施。
(2) 线程安全产生的原因:正确性取决于多个线程的交替执行时序,产生了竞态条件。
(3) 原子类: 应尽量使用原子类,这样会让你分析线程安全时更加方便,但需要注意的是用线程安全类构建的类并不能保证线程安全。例如,一个AtomicInteger get() 和 AtomicInteger set() 是线程安全的,在一个类的一个方法 f()中同时用到了这两个方法,此时的f()就是线程不安全的,因为你不能保证这个复合操作中的get 和 set同时更新。
三:解决机制
1. 加锁。
(1) 锁能使其保护的代码以串行的形式来访问,当给一个复合操作加锁后,能使其成为原子操作。一种错误的思想是只要对写数据的方法加锁,其实这是错的,对数据进行操作的所有方法都需加锁,不管是读还是写。
(2) 加锁时需要考虑性能问题,不能总是一味地给整个方法加锁synchronized就了事了,应该将方法中不影响共享状态且执行时间比较长的代码分离出去。
(3) 加锁的含义不仅仅局限于互斥,还包括可见性。为了确保所有线程都能看见最新值,读操作和写操作必须使用同样的锁对象。
2. 不共享状态
(1) 无状态对象: 无状态对象一定是线程安全的,因为不会影响到其他线程。
(2) 线程关闭: 仅在单线程环境下使用。
3. 不可变对象
可以使用final修饰的对象保证线程安全,由于final修饰的引用型变量(除String外)不可变是指引用不可变,但其指向的对象是可变的,所以此类必须安全发布,也即不能对外提供可以修改final对象的接口。
- JAVA线程安全机制
- java线程安全与同步机制
- java线程安全和锁机制详解
- java线程安全和锁机制详解
- java线程安全和锁机制详解
- java线程安全和锁机制详解
- java如何实现线程的安全:线程的同步机制
- 编写线程安全的Java缓存读写机制 (原创)
- 【线程】Java线程(3)-线程安全解决方案(加锁机制)Atomic && synchronized
- HashMap扩容机制、线程安全
- Java SE学习笔记:创建(Thread/Runable),线程安全,线程同步,同步锁机制
- JAVA安全机制
- java 安全机制
- JAVA的安全机制
- java安全机制
- Java安全机制
- Java 多线程安全机制
- Java线程安全和非线程安全
- EA&UML日拱一卒--序列图(Sequence Diagram)::入门
- View位置及触摸事件
- GPS相关记录
- 集成vue到jquery/bootstrap项目
- maven去除重复jar包
- JAVA线程安全机制
- 怎么在后台将数据库中数据查询出来并分页显示在客户端?!!!
- 446. Arithmetic Slices II
- Nginx安装配置(系统平台:CentOS 7.1 64位)
- 总结巩固知识点
- AngularJS入门之组件化
- Http状态码详解
- 关于Qt/C++和QML获取屏幕大小方法的总结
- ES6-函数的扩展