认识线程安全

     只要存在一个状态变量被一个以上的线程所访问(即被多个函数调用),而且其中的某些线程会写入该变量的情况(即改变该变量的值),便存在着线程安全的隐患,此时,必须使用同步来协调线程该变量的访问。

     如果程序忽略了线程的安全,就存在隐患,任何时刻都有崩溃的可能。如果你想修复这些隐患,可以尝试以下3种方法:

              a.不要跨线程共享变量  

              b.使状态变量不可变 

              c.在任何访问状态变量的地方使用同步

     面向对象技术-------封装数据隐藏,不仅帮助我们编写组织良好的、可维护的类,同时还让我们能更好的实现和维护线程安全。

     线程安全:是指一个类在被多个线程访问时,该类总是能正确的运行不可能存在崩溃的隐患的行为。

(注:下面代码仅仅是做说明使用,不能直接运行)

1.不含状态对象的类永远是线程安全的

         @ThreadSafe

           public class StatelessFactorizer implements Servlet {

                 public void service(ServletRequest req, ServletResponse resp) {

                        BigInteger i = extractFormRequest(req);             //从ServletRequset中解包数据

                        BigInteger[] factors = factor(i);                            //将数据进行因数分解  

                        encodingIntoResponse(resp , factors);              //将结果封包到ServletResponse

                 }

           }

     StatelessFactorizer类中无状态(变量),也没用引用其他类的变量。一个访问 StatelessFactorizer 的线程,不会影响到访问同一个Servlet的其他线程的计算结果,因为两个线程不共享变量,它们如同访问不同的实例。

2.原子操作影响着线程安全

         /** 计算Servlet请求数量 */

           @NotThreadSafe

           public class  UnsafeCountingFactorizer implements Servlet {

                private long count = 0;                     //记录请求数量的变量                      

                public long getCount() { return count; }

                public void service(ServletRequest req, ServletResponse resp) {

                      BigInteger i = extractFormRequest(req);

                      BigInteger[] factors = factor(i);

                      ++count;                                   //每请求一次count自增

                      encodingIntoResponse(resp , factors);

                }

           }

       UnsafeCountingFactorizer并非线程安全的,尽管它在单线程的环境中运行良好。表面上看++count是一个单独的操作,

 但其不是原子操作(作为一个 单独的、不可分割的操作去执行)。于是,++count这么一条语句便是的程序存在了线程安全的隐患。

我们可以设想,同时有A、B两个线程访问 UnsafeCountingFactorizer(假设count初始值为0),则A、B获得的count值都是0,倘若A的操作在B之前完成,则count的值自增成1了,随后B完成操作,问题出来了,B完成后count自增,由于B读取到的count值是0,故B写入count的值为1,覆盖了A写入count中的1。这并不是我们想要的结果,期望中的结果应该是2才对!

 

       粗略的说,原子操作是解决线程安全的主要策略。原子操作能防止多个线程之间对共享变量的写,使得变量出现脏数据的情况。

Java提供了强制原子性的内置锁机制-------synchronized块。

         synchronized(lock) {

              //访问或修改被锁保护的共享变量

              //此块内的所有操作为合成一原子操作,要么全部执行完后释放锁,要么全部不执行

         }

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值