单例模式是指:对于一个类在内存中只能存在唯一一个对象,这种设计模式叫做单例设计模式。
单例设计模式的写法:
1. 设置私有(private)的构造方法。
2. 实例化一个该类的对象作为成员变量,并设置为private、static, 饿汉式还可以加上final。
3. 增加一个public static 的成员方法getInstance,来获取step2 产生的成员变量。
实例:
1. 饿汉式:
1 class Single { 2 private Single(){}; 3 private static final Single s = new Single(); 4 5 public static Single getInstance(){ 6 return s; 7 } 8 }
2. 懒汉式:
1 class Single { 2 private Single(){}; 3 private static Single s = null;// 延迟加载
4 5 public static Single getInstance(){ 6 if(null == s)//双重判断提高效率,后来的就不需要再判断锁内的内容,如果不符合条件就直接return
7 synchronized(Single.class)//同步代码块,该处的锁是这个类的字节码对象 8 { 9 if(null ==s) 10 s = new Single(); 11 } 12 return s; 13 } 14 }
二者的区别就是:懒汉式提供了延迟加载,可以在需要时再根据对象是否存在再实例化对象;但是在多线程时会出现安全问题,因此开发中多使用饿汉式。
懒汉式的安全问题可以采用加锁的方式来解决,synchronized 同步代码块,可以防止在一个线程判断完之后另一个线程切入的问题。而且此处的锁是Single类的字节码对象。
在加上同步锁后,每次代码都要先等锁,然后再判断对象是否存在,会使得效率变低,因此,我们可以在同步锁外面再增加一个判断来提高效率。
关于多线程:
进程: 正在进行中的程序,包括代码和数据。每个进程都有一个执行顺序,叫做执行路径或控制单元。
线程:进程中的一个独立的控制单元就是一个线程,线程控制着进程的执行。每个进程都包含至少一个线程。多个线程共享进程的资源,而CPU根据线程分配时间片。
线程的创建方式有两种:
第一种方式:
1. 定义类AThre继承Thread类。
2. 复写Thread类中的run方法,定义线程执行的代码。
3. new 一个类AThre的对象。
4. 调用该对象的start() 方法。
第二种方式:
1. 定义类BThread 实现Runnable接口。
2. 复写Runnable 类中的run方法。
3. new 一个类BThread的对象。
4. new一个Thread的对象并将Bthread的对象作为实参传递给Thread的构造函数。
5. 调用Thread对象的start() 方法。
note: start() 方法执行了两步操作,创建一个线程,在该线程中调用run方法。而如果直接调用run方法,则是在主线程中执行的run中的代码,没有实现多线程。
关于同步:
同步的前提是,必须有两个或两个以上的线程,而且多个线程使用的是同一个锁。
同步的确定:
1. 明确哪些代码是多线程代码
2. 明确共享数据
3. 明确多线程运行中哪些语句是操作共享数据的。
同步有两种方式,
同步代码块 | 同步函数 |
synchronized(this){} | synchronized 非静态方法 |
synchronized([className].class) | synchronized 静态方法 |