首先了解一下Singleton模式通常的两种表现形式:
第一种形式:
public
class
Singleton {
private
Singleton(){}
//
在自己内部定义自己一个实例,是不是很奇怪?
//
注意这是private 只供内部调用
private
static
Singleton instance
=
new
Singleton();
//
这里提供了一个供外部访问本class的静态方法,可以直接访问
public
static
Singleton getInstance() {
return
instance;
}
}
第二种形式:
public
class
Singleton {
private
static
Singleton instance
=
null
;
public
static
synchronized
Singleton getInstance() {
//
这个方法比上面有所改进,不用每次都进行生成对象,只是第一次
//
使用时生成实例,提高了效率!
if
(instance
==
null
) instance=
new
Singleton();
return
instance;
}
}
使用Singleton.getInstance()可以访问单态类。
上面第二中形式就是lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。
注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。
那么为什么只有使用synchronized关键字才可以达到单态的目的呢?synchronized到底有什么含义呢?
synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。
1.
synchronized 方法
:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:
public
synchronized
void
accessVal(
int
newVal);
synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。
这
种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized
的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变
量的方法均被声明为 synchronized)。
在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
synchronized
方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为
synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized
方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized
,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。
2. synchronized 块
:通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized
(syncObject) {
//
允许访问控制的代码
}
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
对synchronized(this)的一些理解
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用
分享到:
相关推荐
2. 懒汉式(Lazy Initialization): 类加载时不初始化,而是首次调用`getInstance`方法时才实例化。这种方式非线程安全,但在Java 1.5后可以通过`synchronized`关键字保证线程安全。 ```java public class ...
在Java中,单例模式的实现方式多种多样,但常见的有饿汉式(Eager Initialization)和懒汉式(Lazy Initialization)两种。 1. **饿汉式**: 饿汉式是在类加载时就完成了初始化,所以类加载比较慢,但获取对象的...
在"singleton.zip"压缩包中,我们可能会找到几种不同的Java单例实现方式的示例代码,包括饿汉式、懒汉式、反射实现以及内部类实现等。以下是对这些单例模式实现方式的详细解释: 1. **饿汉式(Eager Initialization...
本主题探讨的是线程安全的单例模式实现,特别是饥饿模式(Starvation)和延迟加载(Lazy Initialization)两种策略。 首先,让我们理解什么是线程安全。在多线程环境下,如果一个类的实例可以被多个线程同时访问,...
2. **懒加载**:这种方式实现了**Lazy Initialization**(即懒加载),即仅当第一次调用`getInstance()`方法时才创建实例。 3. **性能优化**:相比于简单的同步方法,这种方式只在首次实例化时进行同步操作,从而...
2. 懒汉式(Lazy Initialization):在第一次调用getInstance()时才创建实例,线程不安全,多线程环境下可能创建多个实例。 ```java public class Singleton { private static Singleton instance; private ...
2. 懒汉式(Lazy Initialization):在第一次需要时才创建单例对象,延迟加载,节省内存。线程不安全,需要进行同步处理。 ```java public class Singleton { private static Singleton INSTANCE; private ...
2. **懒汉式(Lazy Initialization)**:在类被加载后,直到第一次调用getInstance方法时才创建实例,延迟了初始化,但是非线程安全。 ```java public class Singleton { private static Singleton instance; ...
2. 懒汉式(Lazy Initialization): 这种方式在第一次调用`getInstance()`方法时才创建实例,但如果不加同步控制,在多线程环境下可能会创建多个实例。为了确保线程安全,可以使用`synchronized`关键字修饰`...
2. **懒汉式(Lazy Initialization)**:延迟到第一次调用 `getInstance` 方法时才初始化。但在多线程环境下,如果没有同步控制,可能会创建多个实例。 ```java public class Singleton { private static ...
2. **懒汉式(Lazy Initialization)**:首次调用`getInstance()`方法时才初始化,延迟加载,但非线程安全。 ```java public class Singleton { private static Singleton instance; private Singleton() {} ...
Singleton通常采用静态内部类、枚举或懒汉式(Lazy Initialization)来实现。懒汉式是在第一次需要实例时才创建,降低了内存占用,但同时也引入了线程安全问题。如最初的`WorldCup`示例,它通过简单的if条件检查和...
这是最简单的单例模式实现,也称为懒汉式(Lazy Initialization)。在基础版中,`getInstance`方法在`uniqueInstance`为null时才会创建实例,延迟了实例的创建。但这种方式在多线程环境中并不安全,因为多个线程...
- 懒汉式(Lazy Initialization):在第一次调用getInstance时才创建单例对象。如果不使用单例,就不会创建,节省资源。但线程不安全,需要通过同步机制保证。 ```java public class Singleton { private static ...
Lazy Initialization Holder Class(延迟初始化持有类) 另一种实现线程安全的单例模式的方法是使用静态内部类。这种方式利用了Java类加载机制的特性来保证初始化的线程安全性,同时又延迟了单例的初始化过程。 `...
对象序列化之后再反序列化时会生成新的对象,因此当 Singleton 单类模式类实现序列化接口时,必须显式声明所有的字段为 transient,并且提供 readResolve 方法来防止通过序列化破坏单态模式。 除了饱汉模式和饿汉...
在Java或C#等面向对象语言中,实现单件模式通常有两种方法:饿汉式(Eager Initialization)和懒汉式(Lazy Initialization)。 1. 饿汉式:这种实现方式在类加载时就完成了初始化,所以类加载比较慢,但获取实例的...
另一种常见的实现方式是"懒汉式"(Lazy Initialization),它推迟了实例的创建,直到第一次调用`getInstance`方法时才进行。原始的"懒汉式"代码如下: ```java public class Singleton { private static Singleton...
在Java中,单例模式有多种实现方式,主要分为两类:饿汉式(Eager Initialization)和懒汉式(Lazy Initialization)。 1. **饿汉式**: - 饿汉式是在类加载时就完成了初始化,所以类加载比较慢,但获取实例的速度...
在Java中,我们可以采用多种方式来实现单例模式,其中最常见的是懒汉式(Lazy Initialization)和饿汉式(Eager Initialization)。根据提供的文件名`Singleton.java`,我们猜测这里可能实现的是懒汉式单例,因为...