并发安全 ——- 什么是线程安全

  • Post author:
  • Post category:其他


一、

并发(concurrency),简单来说,就是cpu在同一时刻执行多个任务。

而java并发是由多线程实现的;

在jvm的世界里,线程就像不相干的平行空间,串行在虚拟机中(当然线程之间是可以交互的,也并不一定是串行)

多线程的存在就是压榨cpu,提高程序性能,但同时存在线程安全问题。


死锁



脏数据

就是典型的线程安全问题。

简单来说,线程安全就是:

在多线程环境中,能永远保证程序的正确性。



只有

存在共享数据

时才需要考虑线程安全问题。(其中,

方法区





就是主要的线程共享区域。)

当多线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或者协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的;一个很好的线程安全的例子是没有字段和引用的 Servlet 类,因为没有字段和引用所以是

无状态的。


二、状态


1.基本概念

:①

有状态

就是有数据存储功能,

有状态对象(stateful bean)

就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。



无状态

就是一次操作,不能保存数据。

无状态对象(stateless bean)

就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。


2.Spring中的有状态和无状态

无状态的bean适合单例模式,可以共享实例,提高性能;有状态的bean在多线程环境下不安全,适合用prototype模式,每次请求都会创建一个新的bean实例。

默认情况下,spring bean工厂的实例都是singleton单例模式,容器只存在一个共享的bean实例。

理解了两者的关系,那么scope选择的原则就容易多了。例如service层和dao层默认singleton就行,因为不需要状态信息,也就相当于immutable(不可变)类;但是struts2中的User等实体类,是有状态信息的,所以在多线程环境中不安全,所以struts2默认的实现是prototype实现模式。


三、多线程下的并发访问策略

1.java监视器模式:一直使用某一对象的锁来保护某状态;

2.线程安全委托:将类的线程安全性

委托给

某个或多个线程安全的

状态变量;


四、解决机制

1.加锁 :①锁能使其保护的代码以串行的方式被访问,当给一个复合操作加锁后,能使其成为原子操作。一种错误的思想是只给写数据加锁,其实对对数据进行操作的所有方法都需要加锁,不管是读还是写;②加锁时需要考虑性能问题,不能一味的给整个方法加锁synchronized就完事了,应该将方法中不影响共享状态的且执行时间较长的代码分离出去;③加锁的含义不仅仅局限于互斥,还包括可见性。为了确保所有线程都能看到最新值,读操作和写操作必须使用同样的锁对象。

2.不共享状态 :①无状态对象:无状态对象一定是线程安全的,因为不会影响其他线程;

②线程关闭 : 仅在单线程环境下使用。

3.不可变对象 :可以使用final修饰的对象保证线程安全,由于final修饰的引用型变量(除了String)不可变指的是引用不可变,但其指向的对象是可变。



版权声明:本文为castletower原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。