欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Static 关键字的 5 种用法(1静态变量)

程序员文章站 2024-03-17 16:04:10
...

说到static,静态变量和静态方法大家随口就来,因为他们在实际开发中应用很广泛,但他们真正在使用的时候会存在很多问题,而且它的使用不只那两种:

1.静态变量。

2.静态方法。

3.静态代码块。

4.静态内部类。

5.静态导入。

接下来我们看一下这些用法。

1.静态变量
静态变量属于类,内存中只有一个实例,当类被加载,就会为该静态变量分配内存空间,跟 class 本身在一起存放在方法区中永远不会被回收,除非 JVM 退出。(方法区还存哪些东西可以看看:Java虚拟机运行时数据区域)静态变量的使用方式:【类名.变量名】和【对象.变量名】。

【实例】实际开发中的日期格式化类SimpleDateFormat会经常用到,需要的时候会new一个对象出来直接使用,但我们知道频繁的创建对象不好,所以在DateUtil中直接创建一个静态的SimpleDateFormat全局变量,直接使用这个实例进行操作,因为内存共享,所以节省了性能。但是它在高并发情况下是存在线程安全问题的。SimpleDateFormat线程安全问题代码复现:

public class OuterStatic {  
  public static class InnerStaticSimpleDateFormat  implements Runnable {
         @Override
         public void run() {
             while(true) {
                 try {
                   Thread.sleep(3000);
                     System.out.println(Thread.currentThread().getName()
                                 +":"+DateUtil.parse("2017-07-27 08:02:20"));
                 } catch (Exception e) {
                     e.printStackTrace();
                 }
             }
         }    
     }
     public static void main(String[] args) {
         for(int i = 0; i < 3; i++){
            new Thread(new InnerStaticSimpleDateFormat(), "测试线程").start();
           
         }
             
     }
}

class DateUtil {
   
   private static  volatile SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   
   public static  String formatFromDate(Date date)throws ParseException{
       return sdf.format(date);
   }
   public static Date parseToDate(String strDate) throws ParseException{

       return sdf.parse(strDate);
   }
}

虽然有volatile使对象可见,但运行后有一定几率会报java.lang.NumberFormatException: multiple points或For input string: ""等错误,原因是多线程都去操作一个对象(本图来自于:关于 SimpleDateFormat 的非线程安全问题及其解决方案):
Static 关键字的 5 种用法(1静态变量)
解决办法:

使用私有的对象。

加锁。推荐:Java 虚拟机对锁优化所做的努力

ThreadLocal。推荐:多线程并发神器–ThreadLocal

使用第三方的日期处理函数。

5.Java8推出了线程安全、简易、高可靠的时间包,里面有LocalDateTime年月日十分秒;LocalDate日期;LocalTime时间三个类可供使用。推荐:JDK8之新特性扩展篇

下图是使用私有对象和ThreadLocal解决高并发状态的图解。
Static 关键字的 5 种用法(1静态变量)
本文给出使用私有的对象和加锁两种实现代码,ThreadLocal方式读者可以尝试自己实现

public class DateUtil {

   private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     
   public static String formatFromDate(Date date)throws ParseException{
     //方式一:让内存不共享,到用的时候再创建私有对象,使用时注释掉全局变量sdf
     //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     //return sdf.format(date);
     //方式二:加锁,使用时打开全局变量sdf的注释
       synchronized(sdf){
           return sdf.format(date);
       }  
   }
  public static Date parseToDate(String strDate) throws ParseException{
      //方式一:使用时注释掉全局变量sdf
      //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      //return sdf.parse(strDate);
      //方式二:加锁,使用时打开全局变量sdf的注释
       synchronized(sdf){
           return sdf.parse(strDate);
       }
   }
}
相关标签: static java