A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 沫然 中级黑马   /  2014-4-3 13:12  /  1094 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 沫然 于 2014-4-3 19:44 编辑

单例设计模式要不要用到synchronized?


synchronized的用法,做好能举例说明。

5 个回复

倒序浏览
单例的懒汉模式 。  如果多个线程要获得单例,  那么这个懒汉模式就要用synchronized 。
回复 使用道具 举报
如果多个线程同时实例化某懒汉式的单例类,那么就有可能在单例类内部多次初始化实例,造成单例模式失效。因此,对于多线程程序中的懒汉式单例,还需要对其加锁,确保线程安全。

简单地说,synchronized 关键字的用法,主要分为两类:

一是方法定义时,加在方法名之前,形如:synchronized   methodName(params){ ... };

二是声明同步块,形如:synchronized(this) { … }。

其作用是给修饰的方法或者代码块加上同步锁。当一个线程执行到这个方法或者代码块的时候,该部分被锁定,之后的其它执行到这些代码的线程被阻塞,直到上一个线程执行完毕,释放同步锁。

如下的代码是线程安全的懒汉式单例类的实现:

public class Singleton {
    private static Singleton instance;
    private final static Object syncLock = new Object();
   
    private Singleton() {
      
    }
   
    public static Singleton getInstance(){
        if (instance == null) {
            synchronized (syncLock) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
      
        return instance;
    }
}

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
  1. class Single1
  2. {
  3.         private Single1(){}
  4.         private static Single1 s=null;
  5.         public static  Single1 getInstance()
  6.         {
  7.                 if (s==null)
  8.                 {
  9.                         synchronized(Single.class)
  10.                         {
  11.                                 if(s==null)
  12.                                 s=new Single1();
  13.                                
  14.                         }
  15.                 }
  16.                 return s;
  17.                
  18.         }
  19. }
复制代码
单例设计模式懒汉式 需要用到synchronized

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
synchronized(对象) {  // 任意对象都可以。这个对象就是锁。
        需要被同步的代码;
}
好处:解决了线程安全问题。
弊端:相对降低性能,因为判断锁需要消耗资源,产生了死锁。

定义同步是有前提的:
1,必须要有两个或者两个以上的线程,才需要同步。
2,多个线程必须保证使用的是同一个锁。

同步的第二种表现形式:
同步函数:其实就是将同步关键字定义在函数上,让函数具备了同步性。

同步函数是用的哪个锁呢?
通过验证,函数都有自己所属的对象this,所以同步函数所使用的锁就是this锁。

当同步函数被static修饰时,这时的同步用的是哪个锁呢?
静态函数在加载时所属于类,这时有可能还没有该类产生的对象,但是该类的字节码文件加载进内存就已经被封装成了对象,这个对象就是该类的字节码文件对象。
所以静态加载时,只有一个对象存在,那么静态同步函数就使用的这个对象。
这个对象就是 类名.class

同步代码块和同步函数的区别?
同步代码块使用的锁可以是任意对象。
同步函数使用的锁是this,静态同步函数的锁是该类的字节码文件对象。

在一个类中只有一个同步,可以使用同步函数。如果有多同步,必须使用同步代码块,来确定不同的锁。所以同步代码块相对灵活一些。


//懒汉式:延迟加载方式。
当多线程访问懒汉式时,因为懒汉式的方法内对共性数据进行多条语句的操作。所以容易出现线程安全问题。为了解决,加入同步机制,解决安全问题。但是却带来了效率降低。
为了效率问题,通过双重判断的形式解决。
class Single{
        private static Single s = null;
        private Single(){}
        public static Single getInstance(){ //锁是谁?字节码文件对象;
                if(s == null){
                        synchronized(Single.class){
                                if(s == null)
                                        s = new Single();
                        }
                }
                return s;
        }
}
---------------------------------------------------------
同步死锁:通常只要将同步进行嵌套,就可以看到现象。同步函数中有同步代码块,同步代码块中还有同步函数。

线程间通信:思路:多个线程在操作同一个资源,但是操作的动作却不一样。
1:将资源封装成对象。
2:将线程执行的任务(任务其实就是run方法。)也封装成对象。

等待唤醒机制:涉及的方法:
wait:将同步中的线程处于冻结状态。释放了执行权,释放了资格。同时将线程对象存储到线程池中。
notify:唤醒线程池中某一个等待线程。
notifyAll:唤醒的是线程池中的所有线程。

注意:
1:这些方法都需要定义在同步中。
2:因为这些方法必须要标示所属的锁。
        你要知道 A锁上的线程被wait了,那这个线程就相当于处于A锁的线程池中,只能A锁的notify唤醒。
3:这三个方法都定义在Object类中。为什么操作线程的方法定义在Object类中?
        因为这三个方法都需要定义同步内,并标示所属的同步锁,既然被锁调用,而锁又可以是任意对象,那么能被任意对象调用的方法一定定义在Object类中。

wait和sleep区别: 分析这两个方法:从执行权和锁上来分析:
wait:可以指定时间也可以不指定时间。不指定时间,只能由对应的notify或者notifyAll来唤醒。
sleep:必须指定时间,时间到自动从冻结状态转成运行状态(临时阻塞状态)。
wait:线程会释放执行权,而且线程会释放锁。
Sleep:线程会释放执行权,但不是不释放锁。

线程的停止:通过stop方法就可以停止线程。但是这个方式过时了。
停止线程:原理就是:让线程运行的代码结束,也就是结束run方法。
怎么结束run方法?一般run方法里肯定定义循环。所以只要结束循环即可。
第一种方式:定义循环的结束标记。
第二种方式:如果线程处于了冻结状态,是不可能读到标记的,这时就需要通过Thread类中的interrupt方法,将其冻结状态强制清除。让线程恢复具备执行资格的状态,让线程可以读到标记,并结束。


这些 都是多线程 知识点 值得注意的地方   同步

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
多个线程要得到单例,  懒汉模式就得用synchronized
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马