Static 关键字的 5 种用法(1静态变量)
说到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 的非线程安全问题及其解决方案):
解决办法:
使用私有的对象。
加锁。推荐:Java 虚拟机对锁优化所做的努力
ThreadLocal。推荐:多线程并发神器–ThreadLocal
使用第三方的日期处理函数。
5.Java8推出了线程安全、简易、高可靠的时间包,里面有LocalDateTime年月日十分秒;LocalDate日期;LocalTime时间三个类可供使用。推荐:JDK8之新特性扩展篇
下图是使用私有对象和ThreadLocal解决高并发状态的图解。
本文给出使用私有的对象和加锁两种实现代码,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 关键字的 5 种用法(1静态变量)
-
C#中的static静态变量的用法
-
C#中static静态变量的用法实例
-
C#中static静态变量的用法实例
-
pow函数(数学次方)在c语言的用法,两种编写方法实例( 计算1/1-1/2+1/3-1/4+1/5 …… + 1/99 - 1/100 的值)
-
Java静态static关键字用法。Arrays工具类的用法
-
pow函数(数学次方)在c语言的用法,两种编写方法实例( 计算1/1-1/2+1/3-1/4+1/5 …… + 1/99 - 1/100 的值)
-
Java静态static关键字用法。Arrays工具类的用法
-
避免常见的六种HTML5错误用法 (1)
-
php static静态变量修饰符的用法详解