Chinaunix首页 | 论坛 | 博客
  • 博客访问: 424007
  • 博文数量: 23
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 233
  • 用 户 组: 普通用户
  • 注册时间: 2017-11-28 16:33
文章分类

全部博文(23)

文章存档

2020年(3)

2019年(9)

2018年(10)

2017年(1)

我的朋友

分类: Java

2019-04-25 16:54:25

synchronized与lock:
1. synchronized是java内置关键字,在jvm层面,Lock是个java类;
2. synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
3. synchronized会自动释放锁(线程执行完同步代码会释放锁,线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成死锁;
4. 用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2 等待。如果线程1阻塞,线程2则会一直等待下去,而Lock就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
5.Synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可),Lock锁适合大量同步的代码的同步问题,synchronized锁适合少量的同步问题。

      单例模式,是一个非常重要的一个设计模式,大多数程序员都可以很轻易的写出来,但是想要写出一个完美的单例模式却不简单。并发问题是需要考虑到的,一旦没做好并发控制,就有可能产生多个实例,从而破坏的单例。Java中,synchronized和lock等是最常见的并发控制。下面是几个单例模式的实现:
      枚举:

点击(此处)折叠或打开

  1. public enum Singleton {
  2.     INSTANCE;
  3.     public void whateverMethod() {
  4.     }
  5. }
     静态内部类:

点击(此处)折叠或打开

  1. public class Singleton {
  2.     private static class SingletonHolder {
  3.     private static final Singleton INSTANCE = new Singleton();
  4.     }
  5.     private Singleton (){}
  6.     public static final Singleton getInstance() {
  7.     return SingletonHolder.INSTANCE;
  8.     }
  9. }
     饿汉:

点击(此处)折叠或打开

  1. public class Singleton {
  2.     private static Singleton instance = new Singleton();
  3.     private Singleton (){}
  4.     public static Singleton getInstance() {
  5.     return instance;
  6.     }
  7. }
     饿汉变种:

点击(此处)折叠或打开

  1. public class Singleton {
  2.     private static class SingletonHolder {
  3.     private static final Singleton INSTANCE = new Singleton();
  4.     }
  5.     private Singleton (){}
  6.     public static final Singleton getInstance() {
  7.     return SingletonHolder.INSTANCE;
  8.     }
  9. }
      相信有经验的行家都可以看出来,以上几种方法,虽然没有在代码中显示的使用synchronized,但是,都是借助了ClassLoader的线程安全机制。而ClassLoader的线程安全机制底层也是使用了synchronized的。其中两个“饿汉”,其实是通过定义静态成员变量,以保证instance可以在类初始化的时候被实例化,类的初始化是由ClassLoader完成的,这其实就是利用了ClassLoader的线程安全机制。
      对于静态内部类,这种方式是Singleton类被装载了,instance不一定被初始化,做法上相对于两种饿汉方式稍微优化了一点,因为SingletonHolder类没有被主动使用,只有通过调用getInstance方法时,擦爱会装载SingletonHolder类,从而实例化instance,原理和饿汉是一样的。如果把枚举类进行反序列化,你也会发现他也是使用了static final来修饰每一个枚举项。
      如何不使用synchronized和lock来实现线程安全的单例?答案是CAS,很多乐观锁都是基于CAS实现的,CAS不适使用传统的锁机制来保证线程安全的,是一种基于忙等待的算法,依赖底层硬件,可以支持较大的并行度,但是有一个重要的缺点,如果忙等待一直执行不成功,会对CPU造成较大的执行开销,而且这种写法如果有多个线程同时执行singleton = new Singleton();也会比较浪费堆内存,借助CAS实现的单例模式:

点击(此处)折叠或打开

  1. public class Singleton {
  2.     private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();

  3.     private Singleton() {}

  4.     public static Singleton getInstance() {
  5.         for (;;) {
  6.             Singleton singleton = INSTANCE.get();
  7.             if (null != singleton) {
  8.                 return singleton;
  9.             }

  10.             singleton = new Singleton();
  11.             if (INSTANCE.compareAndSet(null, singleton)) {
  12.                 return singleton;
  13.             }
  14.         }
  15.     }
  16. }







阅读(2979) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~