• java 无状态和有状态区别


    

    诸位Java程序员,想必大家对SimpleDateFormat并不陌生。不过,你是否知道,SimpleDateFormat不是线程安全的(thread safe)。这意味着,下面的代码是错误的:

    class Sample {
      private static final DateFormat format = new SimpleDateFormat("yyyy.MM.dd");
        
      public String getCurrentDateText() {
        return format.format(new Date());
      }
    }

    从功能的角度上看,单独执行这段代码是没有问题的,但放到多线程环境下,因为SimpleDateFormat不是线程安全的,这段代码就会出错。所以,要想让这段代码正确,我们只要稍做微调:

    public class Sample {
        public String getCurrentDateText() {
            return new SimpleDateFormat("yyyy.MM.dd").format(new Date());
        }
    }
    
    

    不知你是否注意到,这里的调整只是由原来的共享format这个变量,变成了每次调用这个方法时创建出一个新的SimpleDateFormat变量。

    作为一个专业程序员,我们当然知道,相比于共享一个变量的开销要比每次创建小。之所以我们必须这么做,是因为SimpleDateFormat不是线程安全的。但从SimpleDateFormat提供给我们的接口上来看,实在让人看不出它与线程安全有和相干。那接下来,我们就要打开JDK的源码,看一下其中的代码之丑。

    如果你手头没有JDK的源码,这里是个不错的参考。

    在format方法里,有这样一段代码:

    calendar.setTime(date);
    
    

    其中,calendar是DateFormat的protected字段。这条语句改变了calendar,稍后,calendar还会用到(在subFormat方法里),而这就是引发问题的根源。

    想象一下,在一个多线程环境下,有两个线程持有了同一个SimpleDateFormat的实例,分别调用format方法:

    1. 线程1调用format方法,改变了calendar这个字段。

    2. 中断来了。

    3. 线程2开始执行,它也改变了calendar。

    4. 又中断了。

    5. 线程1回来了,此时,calendar已然不是它所设的值,而是走上了线程2设计的道路。

    6. BANG!!! 稍微花点时间分析一下format的实现,我们便不难发现,用到calendar,唯一的好处,就是在调用subFormat时,少了一个参数,却带来了这许多的问题。其实,只要在这里用一个局部变量,一路传递下去,所有问题都将迎刃而解。

    这个问题背后隐藏着一个更为重要的问题:无状态。

    无状态方法的好处之一,就是它在各种环境下,都可以安全的调用。衡量一个方法是否是有状态的,就看它是否改动了其它的东西,比如全局变量,比如实例的字段。format方法在运行过程中改动了SimpleDateFormat的calendar字段,所以,它是有状态的。

    写程序,我们要尽量编写无状态方法。

    ------------------------------------------------------------------------------------------------------------------

    有状态:

    Java对象的状态用属性来表示,有属性,也就是对象的变量,就表示是有状态的,有状态就是线程不安全的。

    关于线程安全:

    1) 常量始终是线程安全的,因为只存在读操作。 

    2)每次调用方法前都新建一个实例是线程安全的,因为不会访问共享的资源。

    3)局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量和方法内变量。 

  • 相关阅读:
    九、springboot整合RabbitMq 用死信队列做延迟队列
    八、RabbitMq死信队列与延迟队列
    七、RabbitMq交换机
    六、RabbitMq 发布确认模式(confirm模式)
    五、RabbitMq的消息应答机制
    四、RabbitMq的工作模式( Work Queues)
    三、RabbitMq简单模式(hello world)
    qt 使用属性设置替换样式,为无setstylesheet接口的的action设置样式
    SpringBoot配置国际化
    基于策略模式的前端表单设计
  • 原文地址:https://www.cnblogs.com/nizuimeiabc1/p/4254127.html
Copyright © 2020-2023  润新知