建站学 - 轻松建站从此开始!

建站学-个人建站指南,网页制作,网站设计,网站制作教程

当前位置: 建站学 > 网站开发 > Java教程 >

java什么是线程安全

时间:2019-08-13 14:45来源:PHP中文网 作者:猪哥 点击:
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。在线程安全类中封装了必要的同步机制,客户端无需采用同步措施
要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的和可变的状态的访问。当多个线程访问某个状态变量,并且其中有一个线程执行写入操作时,必须采用同步机制来协调这些线程对变量的访问。无状态对象一定是线程安全的。

如果我们在无状态的对象中增加一个状态时,会出现什么情况呢?

假设我们按照以下方式在servlet中增加一个"命中计数器"来管理请求数量:在servlet中增加一个long类型的域,每处理一个请求就在这个值上加1。

public class UnsafeCountingFactorizer implements Servlet {
     private long count = 0;
 
     public long getCount() {
            return count ;
     }
 
     @Override
     public void service(ServletRequest arg0, ServletResponse arg1)
                 throws ServletException, IOException {
            // do something
           count++;
     }
}

不幸的是,以上代码不是线程安全的,因为count++并非是原子操作,实际上,它包含了三个独立的操作:读取count的值,将值加1,然后将计算结果写入count。如果线程A读到count为10,马上线程B读到count也为10,线程A加1写入后为11,线程B由于已经读过count值为10,执行加1写入后依然为11,这样就丢失了一次计数。

在并发编程中,这种由于不恰当的执行时序而出现不正确的结果是一种非常重要的情况,它有一个正式的名字:竞态条件。最常见的竞态条件类型就是“先检查后执行”操作,即通过一个可能失效的观测结果来决定下一步操作,

延迟初始化是竞态条件的常见情形:

public class LazyInitRace {
     private SomeObject instance = null;
     public SomeObject getInstance() {
            if(instance == null)
                 instance = new SomeObject();
            return instance ;
     }
}

在LazyInitRace中包含竞态条件:首先线程A判断instance为null,然后线程B判断instance也为null,之后线程A和线程B分别创建对象,这样对象就进行了两次初始化,发生错误。

要避免静态条件,就必须在某个线程修改变量时,通过某种方式防止其他线程使用这个变量,从而确保其他线程只能在修改操作完成之前或之后读取和修改状态,而不是在修改状态的过程中。
在UnsafeCountingFactorizer 例子中,线程不安全的原因是count ++并非原子操作,我们可以使用原子类,确保加操作是原子的,

这样类就是线程安全的了:

 public class CountingFactorizer implements Servlet {
     private final AtomicLong count = new AtomicLong(0);
 
    public long getCount() {
          return count .get() ;
   }
 
    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
               throws ServletException, IOException {
          // do something
          count.incrementAndGet();
   }
}

AtomicLong是java.util.concurrent.atomic包中的原子变量类,它能够实现原子的自增操作,这样就是线程安全的了。

(责任编辑:admin)
织梦二维码生成器
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片