前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java并发编程与高并发之安全发布对象

Java并发编程与高并发之安全发布对象

作者头像
别先生
发布2020-02-12 23:21:01
5890
发布2020-02-12 23:21:01
举报
文章被收录于专栏:别先生别先生

1、安全发布对象的发布与逃逸。

  发布对象,使一个对象能够被当前范围之外的代码所使用。

  对象逸出,一种错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见。

  如果不正确的发布了可变对象,会造成两种错误,首先是发布线程以外的任何线程都可以看到被发布对象的过期的值。其次呢,线程看到的被发布对象的引用是最新的,然而呢,被发布对象的状态却是过期的,如果一个对象是可变对象,那么它就要被安全发布才可以。

2、安全发布对象的四种方式。

  1)、第一种,在静态初始化函数中初始化一个对象引用。   2)、第二种,将对象的引用保存到volatile类型域或者AtomicReference对象中。   3)、第三种,将对象的引用保存到某个正确构造对象的final类型域中。   4)、第四种,将对象的引用保存到一个由锁保护的域中。

2.1、懒汉模式 ,单例实例在第一次使用时进行创建,单线程运行没有问题的,但是多线程可能在getInstance出现线程不安全的情况。

代码语言:javascript
复制
 1 package com.bie.concurrency.example.singleton;
 2 
 3 import com.bie.concurrency.annoations.NotThreadSafe;
 4 
 5 /**
 6  * 
 7  *
 8  * @Title: SingletonExample1.java
 9  * @Package com.bie.concurrency.example.singleton
10  * @Description: TODO
11  * @author biehl
12  * @date 2020年1月6日
13  * @version V1.0
14  * 
15  *          1、懒汉模式 ,单例实例在第一次使用时进行创建
16  * 
17  *          2、单线程运行没有问题的,但是多线程可能在getInstance出现线程不安全的情况
18  * 
19  *          3、第一种,在静态初始化函数中初始化一个对象引用。
20  * 
21  */
22 @NotThreadSafe
23 public class SingletonExample1 {
24 
25     // 私有的默认构造方法,避免外部通过new创建对象。
26     private SingletonExample1() {
27     }
28 
29     // 定义单例对象,至少保证有一个对象被创建的。
30     private static SingletonExample1 singletonExample1 = null;
31 
32     // 静态工厂方法
33     public static SingletonExample1 getInstance() {
34         // 判断对象是否为null和创建对象,此处导致了线程不安全
35         if (null == singletonExample1) {
36             singletonExample1 = new SingletonExample1();
37         }
38         return singletonExample1;
39     }
40 
41 }

2.2、饿汉模式 ,单例实例在类装载时进行创建,饿汉模式是线程安全的。饿汉模式,如果单例类构造方法中没有过多的操作处理,饿汉模式是可以接受的。饿汉模式的缺点,如果单例类构造方法中存在过多的操作处理,会导致该类加载的过慢。可能会引起性能问题。

代码语言:javascript
复制
 1 package com.bie.concurrency.example.singleton;
 2 
 3 import javax.annotation.concurrent.ThreadSafe;
 4 
 5 /**
 6  * 
 7  *
 8  * @Title: SingletonExample1.java
 9  * @Package com.bie.concurrency.example.singleton
10  * @Description: TODO
11  * @author biehl
12  * @date 2020年1月6日
13  * @version V1.0
14  * 
15  *          1、饿汉模式 ,单例实例在类装载时进行创建,饿汉模式是线程安全的。
16  * 
17  *          2、饿汉模式,如果单例类构造方法中没有过多的操作处理,饿汉模式是可以接受的。
18  * 
19  *          3、饿汉模式的缺点,如果单例类构造方法中存在过多的操作处理,会导致该类加载的过慢。可能会引起性能问题。
20  * 
21  *          4、第一种,在静态初始化函数中初始化一个对象引用。
22  * 
23  */
24 @ThreadSafe
25 public class SingletonExample2 {
26 
27     // 私有的默认构造方法,避免外部通过new创建对象。
28     // 饿汉模式,私有构造方法没有过多处理。饿汉模式创建的对象肯定会在实际中被使用,不会造成资源浪费。
29     private SingletonExample2() {
30     }
31 
32     // 定义单例对象,至少保证有一个对象被创建的。在类装载的时候进行创建保证了线程的安全性。
33     private static SingletonExample2 singletonExample2 = new SingletonExample2();
34 
35     // 静态工厂方法
36     public static SingletonExample2 getInstance() {
37         return singletonExample2;
38     }
39 
40 }

2.3、懒汉模式 ,单例实例在第一次使用时进行创建,方法加synchronized修饰,不推荐,虽然保证了线程安全性,但是带来了性能方面的开销。

代码语言:javascript
复制
 1 package com.bie.concurrency.example.singleton;
 2 
 3 import com.bie.concurrency.annoations.NotRecommend;
 4 import com.bie.concurrency.annoations.ThreadSafe;
 5 
 6 /**
 7  * 
 8  *
 9  * @Title: SingletonExample1.java
10  * @Package com.bie.concurrency.example.singleton
11  * @Description: TODO
12  * @author biehl
13  * @date 2020年1月6日
14  * @version V1.0
15  * 
16  *          1、懒汉模式 ,单例实例在第一次使用时进行创建
17  * 
18  *          2、方法加synchronized修饰,不推荐,虽然保证了线程安全性,但是带来了性能方面的开销。
19  * 
20  *          3、第四种,将对象的引用保存到一个由锁保护的域中。
21  */
22 @ThreadSafe
23 @NotRecommend
24 public class SingletonExample3 {
25 
26     // 私有的默认构造方法,避免外部通过new创建对象。
27     private SingletonExample3() {
28     }
29 
30     // 定义单例对象,至少保证有一个对象被创建的。
31     private static SingletonExample3 singletonExample3 = null;
32 
33     // 静态工厂方法
34     // 使用synchronized修饰,方法内部所有实现同一时间内只能由一个线程访问。
35     // 因此可以保证线程安全的。
36     public static synchronized SingletonExample3 getInstance() {
37         if (null == singletonExample3) {
38             singletonExample3 = new SingletonExample3();
39         }
40         return singletonExample3;
41     }
42 
43 }

2.4、懒汉模式,【双重同步锁单例模式 】,单例实例在第一次使用时进行创建,此实现是,线程不安全的,JVM和cpu优化,发生了指令重排。

代码语言:javascript
复制
 1 package com.bie.concurrency.example.singleton;
 2 
 3 import com.bie.concurrency.annoations.NotThreadSafe;
 4 
 5 /**
 6  * 
 7  *
 8  * @Title: SingletonExample1.java
 9  * @Package com.bie.concurrency.example.singleton
10  * @Description: TODO
11  * @author biehl
12  * @date 2020年1月6日
13  * @version V1.0
14  * 
15  *          1、懒汉模式,【双重同步锁单例模式 】,单例实例在第一次使用时进行创建
16  * 
17  *          2、此实现是,线程不安全的,JVM和cpu优化,发生了指令重排
18  * 
19  */
20 @NotThreadSafe
21 public class SingletonExample4 {
22 
23     // 1、memory = allocate() 分配对象的内存空间
24     // 2、ctorInstance() 初始化对象
25     // 3、instance = memory 设置instance指向刚分配的内存
26 
27     // JVM和cpu优化,发生了指令重排
28 
29     // 1、memory = allocate() 分配对象的内存空间
30     // 3、instance = memory 设置instance指向刚分配的内存
31     // 2、ctorInstance() 初始化对象
32 
33     // 私有的默认构造方法,避免外部通过new创建对象。
34     private SingletonExample4() {
35     }
36 
37     // 定义单例对象,至少保证有一个对象被创建的。
38     private static SingletonExample4 singletonExample4 = null;
39 
40     // 静态工厂方法
41     public static SingletonExample4 getInstance() {
42         // 双重检测机制
43         if (singletonExample4 == null) {
44             // 同步锁,判断对象不为空以后,锁着SingletonExample4类
45             // synchronized修饰的内部,同一时间只能由一个线程可以访问的。
46             synchronized (SingletonExample4.class) {
47                 // 再次进行判断,如果singletonExample4为空,就进行创建对象。
48                 if (singletonExample4 == null) {
49                     singletonExample4 = new SingletonExample4();
50                 }
51             }
52         }
53         return singletonExample4;
54     }
55 
56 }

2.5、懒汉模式,【双重同步锁单例模式 】,单例实例在第一次使用时进行创建,此实现是,线程安全的,volatile禁止指令重排序。

代码语言:javascript
复制
 1 package com.bie.concurrency.example.singleton;
 2 
 3 import com.bie.concurrency.annoations.ThreadSafe;
 4 
 5 /**
 6  * 
 7  *
 8  * @Title: SingletonExample1.java
 9  * @Package com.bie.concurrency.example.singleton
10  * @Description: TODO
11  * @author biehl
12  * @date 2020年1月6日
13  * @version V1.0
14  * 
15  *          1、懒汉模式,【双重同步锁单例模式 】,单例实例在第一次使用时进行创建
16  * 
17  *          2、此实现是,线程安全的,volatile禁止指令重排序。
18  * 
19  *          3、第二种,将对象的引用保存到volatile类型域或者AtomicReference对象中。
20  * 
21  */
22 @ThreadSafe
23 public class SingletonExample5 {
24 
25     // 1、memory = allocate() 分配对象的内存空间
26     // 2、ctorInstance() 初始化对象
27     // 3、instance = memory 设置instance指向刚分配的内存
28 
29     // 私有的默认构造方法,避免外部通过new创建对象。
30     private SingletonExample5() {
31     }
32 
33     // 定义单例对象,至少保证有一个对象被创建的。
34     // 单例对象 volatile + 双重检测机制 -> 禁止指令重排
35     // volatile适用场景做状态标识量、双重检测,此处就是volatile的双重检测使用场景。
36     private volatile static SingletonExample5 singletonExample4 = null;
37 
38     // 静态工厂方法
39     public static SingletonExample5 getInstance() {
40         // 双重检测机制
41         if (singletonExample4 == null) {
42             // 同步锁,判断对象不为空以后,锁着SingletonExample4类
43             // synchronized修饰的内部,同一时间只能由一个线程可以访问的。
44             synchronized (SingletonExample5.class) {
45                 // 再次进行判断,如果singletonExample4为空,就进行创建对象。
46                 if (singletonExample4 == null) {
47                     singletonExample4 = new SingletonExample5();
48                 }
49             }
50         }
51         return singletonExample4;
52     }
53 
54 }

2.6、饿汉模式 ,单例实例在类装载时进行创建,饿汉模式是线程安全的。

代码语言:javascript
复制
 1 package com.bie.concurrency.example.singleton;
 2 
 3 import javax.annotation.concurrent.ThreadSafe;
 4 
 5 /**
 6  * 
 7  *
 8  * @Title: SingletonExample1.java
 9  * @Package com.bie.concurrency.example.singleton
10  * @Description: TODO
11  * @author biehl
12  * @date 2020年1月6日
13  * @version V1.0
14  * 
15  *          1、饿汉模式 ,单例实例在类装载时进行创建,饿汉模式是线程安全的。
16  *
17  * 
18  */
19 @ThreadSafe
20 public class SingletonExample6 {
21 
22     // 私有的默认构造方法,避免外部通过new创建对象。
23     // 饿汉模式,私有构造方法没有过多处理。饿汉模式创建的对象肯定会在实际中被使用,不会造成资源浪费。
24     private SingletonExample6() {
25     }
26 
27     // 定义单例对象,至少保证有一个对象被创建的。在类装载的时候进行创建保证了线程的安全性。
28     private static SingletonExample6 singletonExample6 = null;
29 
30     // 静态块初始化对象singletonExample6
31     static {
32         singletonExample6 = new SingletonExample6();
33     }
34 
35     // 静态工厂方法
36     public static SingletonExample6 getInstance() {
37         return singletonExample6;
38     }
39 
40     public static void main(String[] args) {
41         System.out.println(getInstance().hashCode());
42         System.out.println(getInstance().hashCode());
43     }
44 
45 }

2.7、枚举方式。线程安全,推荐的方式。相比于懒汉模式,在安全性方面更容易保证,在饿汉模式,在安全性方面,在实际调用方面才可以初始化,不会造成资源的浪费。

代码语言:javascript
复制
 1 package com.bie.concurrency.example.singleton;
 2 
 3 import javax.annotation.concurrent.ThreadSafe;
 4 
 5 import com.bie.concurrency.annoations.Recommend;
 6 
 7 /**
 8  * 
 9  *
10  * @Title: SingletonExample1.java
11  * @Package com.bie.concurrency.example.singleton
12  * @Description: TODO
13  * @author biehl
14  * @date 2020年1月6日
15  * @version V1.0
16  * 
17  *          1、枚举方式。线程安全,推荐的方式。
18  * 
19  *          2、相比于懒汉模式,在安全性方面更容易保证,在饿汉模式,在安全性方面,在实际调用方面才可以初始化,不会造成资源的浪费。
20  * 
21  */
22 @ThreadSafe
23 @Recommend
24 public class SingletonExample7 {
25 
26     // 私有的默认构造方法,避免外部通过new创建对象。
27     private SingletonExample7() {
28     }
29 
30     // 静态工厂方法
31     public static SingletonExample7 getInstance() {
32         return Singleton.INSTANCE.getInstance();
33     }
34 
35     // 枚举类,私有的枚举类。
36     private enum Singleton {
37         // instance
38         INSTANCE;
39 
40         // 私有的类的实例
41         private SingletonExample7 singletonExample7;
42 
43         // JVM保证这个方法绝对只调用一次
44         // 枚举类的构造方法
45         Singleton() {
46             singletonExample7 = new SingletonExample7();
47         }
48 
49         // 提供一个方法方便类来获取
50         public SingletonExample7 getInstance() {
51             // 返回枚举类里面的实例
52             return singletonExample7;
53         }
54     }
55 
56 }

作者:别先生 博客园:https://www.cnblogs.com/biehongli/

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-01-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档