??xml version="1.0" encoding="utf-8" standalone="yes"?> 专注于分享Java后端相关技术、老司机实战干货,不限于JVM、ƈ发、设计模式、性能优化、分布式&微服务、云原生、大数据相关主题?/span>
Java爱好者社?/strong>
公众号内容简介:
希望x的你停下脚步Q定有所收获?/span>
以前的个人博客内容不好迁U,所以我打算Ҏ(gu)自己的多q经验,不断整理输出有h(hun)值的内容?br />目前公众号内Ҏ(gu)关于SpringCloudQ微服务框架Q、SkywalkingQAPM监控调用链)、JVMQGC分析、内存泄漏分析)、ƈ发编E?/span>相关原创实战文章已出炉?br />
最q刚开始已l有不少伙伴关注了Q期待能有幸搜烦到本博客的同学,可以扫码x一下,不胜感激?br />大家有Q何技术、职场、面试上的问题都可以与我交流?br />
方式一Q?/strong>扫码以下公众号二l码Q?/strong>
方式二:在微信上直接搜烦Q?nbsp;javatech_cbo
感谢各位伙伴的支持Q后l会在该公众号上输出大量的有价值的实战q货 Q期待与你一同进步与成长?br />
]]>
]]>
]]>
对于Frame而言QPlaylist是一个容器,然而Playlist也实作PlayableQ所以它也可以播放,(zhn)可以进一步地Playlistl合臛_一个Playlist中,以Ş成更长的播放清单。以Java实现的话?br />以Java實現的話?br />import java.util.*;
interface Playable {
void play();
}
class Frame implements Playable {
private String image;
Frame(String image) {
this.image = image;
}
public void play() {
System.out.println("播放 " + image);
}
}
class Playlist implements Playable {
private List<Playable> list = new ArrayList<Playable>();
public void add(Playable playable) {
list.add(playable);
}
public void play() {
for(Playable playable : list) {
playable.play();
}
}
}
public class Main {
public static void main(String[] args) {
Frame logo = new Frame("片頭 LOGO");
Playlist playlist1 = new Playlist();
playlist1.add(new Frame("Duke 左揮?));
playlist1.add(new Frame("Duke x?));
Playlist playlist2 = new Playlist();
playlist2.add(new Frame("Duke 走左?));
playlist2.add(new Frame("Duke 走右?));
Playlist all = new Playlist();
all.add(logo);
all.add(playlist1);
all.add(playlist2);
all.play();
}
}
以Python實現的話Q?br />class Frame:
all.play();以UML来表CComposite模式的结构:
def __init__(self, image):
self.image = image
def play(self):
print("播放 " + self.image)
class Playlist:
def __init__(self):
self.list = []
def add(self, playable):
self.list.append(playable);
def play(self):
for playable in self.list:
playable.play()
logo = Frame("片頭 LOGO")
playlist1 = Playlist()
playlist1.add(Frame("Duke 左揮?))
playlist1.add(Frame("Duke x?))
playlist2 = Playlist()
playlist2.add(Frame("Duke 走左?))
playlist2.add(Frame("Duke 走右?))
all = Playlist()
all.add(logo)
all.add(playlist1)
all.add(playlist2)
h层次性或l合性的物g可以使用Composite模式Q像是电(sh)路元件、视H元件等Q用Composite模式可以大大减低q些元g设计的复杂度Q以Java标准API中AWT视窗元gZQ?/small>Component上有个paint()Ҏ(gu)Q可以进行元件的l制Q?/small>Container可以容纳ComponentQ如Button、Label{)Q而Containerl承ComponentQ所以Container也可以容UContainerQ这也是Composite模式的实际例子:
from Q?nbsp;http://caterpillar.onlyfun.net/Gossip/index.html
]]>
在开发中Q如果某个实例的创徏需要消耗很多系l资源,那么我们通常会用惰性加载机Ӟ也就是说只有当用到q个实例的时候才会创个实例,q个好处在单例模式中得到了广泛应用。这个机制在single-threaded环境下的实现非常单,然而在multi-threaded环境下却存在隐?zhn)。本文重点介l惰性加载机制以及其在多U程环境下的使用Ҏ(gu)。(作者numberzeroQ参考IBM文章《Double-checked locking and the Singleton pattern》,Ƣ迎转蝲与讨论)
1 单例模式的惰性加?br /> 通常当我们设计一个单例类的时候,会在cȝ内部构造这个类Q通过构造函敎ͼ或者在定义处直接创建)Qƈ对外提供一个static getInstanceҎ(gu)提供获取该单例对象的途径。例如:
Java代码 < type="application/x-shockwave-flash" width="14" height="15" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=public%20class%20Singleton%20%20%20%20%20%20%0A%7B%20%20%20%20%20%20%0A%20%20%20%20private%20static%20Singleton%20instance%20%3D%20new%20Singleton()%3B%20%20%20%20%20%20%0A%20%20%20%20private%20Singleton()%7B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%E2%80%A6%20%20%20%20%20%20%0A%20%20%20%20%7D%20%20%20%20%20%20%0A%20%20%20%20public%20static%20Singleton%20getInstance()%7B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20return%20instance%3B%20%20%20%20%20%20%20%0A%20%20%20%20%7D%20%20%20%20%20%20%0A%7D%20%20%20%20%20%0A" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14">
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton(){
…
}
public static Singleton getInstance(){
return instance;
}
}
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton(){
…
}
public static Singleton getInstance(){
return instance;
}
}
q样的代码缺Ҏ(gu)Q第一ơ加载类的时候会q带着创徏Singleton实例Q这L(fng)l果与我们所期望的不同,因ؓ创徏实例的时候可能ƈ不是我们需要这个实例的时候。同时如果这个Singleton实例的创建非常消耗系l资源,而应用始l都没有使用Singleton实例Q那么创建Singleton消耗的pȝ资源p白白费了?/p>
Z避免q种情况Q我们通常使用惰性加载的机制Q也是在用的时候才d建。以上代码的惰性加载代码如下:
Java代码 < type="application/x-shockwave-flash" width="14" height="15" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=public%20class%20Singleton%7B%20%20%20%20%20%20%0A%20%20%20%20private%20static%20Singleton%20instance%20%3D%20null%3B%20%20%20%20%20%20%0A%20%20%20%20private%20Singleton()%7B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%E2%80%A6%20%20%20%20%20%20%0A%20%20%20%20%7D%20%20%20%20%20%20%0A%20%20%20%20public%20static%20Singleton%20getInstance()%7B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20if%20(instance%20%3D%3D%20null)%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20instance%20%3D%20new%20Singleton()%3B%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20instance%3B%20%20%20%20%20%20%20%0A%20%20%20%20%7D%20%20%20%20%20%20%0A%7D%20%20%20%20%20%0A" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14">
public class Singleton{
private static Singleton instance = null ;
private Singleton(){
…
}
public static Singleton getInstance(){
if (instance == null )
instance = new Singleton();
return instance;
}
}
public class Singleton{
private static Singleton instance = null;
private Singleton(){
…
}
public static Singleton getInstance(){
if (instance == null)
instance = new Singleton();
return instance;
}
}
q样Q当我们W一ơ调用Singleton.getInstance()的时候,q个单例才被创徏Q而以后再ơ调用的时候仅仅返回这个单例就可以了?/p>
2 惰性加载在多线E中的问?br /> 先将惰性加载的代码提取出来Q?nbsp;
Java代码 < type="application/x-shockwave-flash" width="14" height="15" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=public%20static%20Singleton%20getInstance()%7B%20%20%20%20%20%20%0A%20%20%20%20if%20(instance%20%3D%3D%20null)%20%20%20%20%20%20%0A%20%20%20%20instance%20%3D%20new%20Singleton()%3B%20%20%20%20%20%20%20%0A%20%20%20%20return%20instance%3B%20%20%20%20%20%20%20%0A%7D%20%20%20%20" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14">
public static Singleton getInstance(){
if (instance == null )
instance = new Singleton();
return instance;
}
public static Singleton getInstance(){
if (instance == null)
instance = new Singleton();
return instance;
} q是如果两个U程A和B同时执行了该Ҏ(gu)Q然后以如下方式执行Q?/p>
1. Aq入if判断Q此时foo为nullQ因此进入if?/p>
2. Bq入if判断Q此时Aq没有创建fooQ因此foo也ؓnullQ因此B也进入if?/p>
3. A创徏了一个Fooq返?/p>
4. B也创Z一个Fooq返?/p>
此时问题出现了,我们的单例被创徏了两ơ,而这q不是我们所期望的?/p>
3 各种解决Ҏ(gu)及其存在的问?br /> 3.1 使用Class锁机?br /> 以上问题最直观的解军_法就是给getInstanceҎ(gu)加上一个synchronize前缀Q这hơ只允许一个现成调用getInstanceҎ(gu)Q?/p>
Java代码 < type="application/x-shockwave-flash" width="14" height="15" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=public%20static%20synchronized%20Singleton%20getInstance()%7B%20%20%20%20%20%20%0A%20%20%20%20if%20(instance%20%3D%3D%20null)%20%20%20%20%20%20%0A%20%20%20%20instance%20%3D%20new%20Singleton()%3B%20%20%20%20%20%20%20%0A%20%20%20%20return%20instance%3B%20%20%20%20%20%20%20%0A%7D%20%20%20%20%20%0A" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14">
public static synchronized Singleton getInstance(){
if (instance == null )
instance = new Singleton();
return instance;
}
public static synchronized Singleton getInstance(){
if (instance == null)
instance = new Singleton();
return instance;
}
q种解决办法的确可以防止错误的出玎ͼ但是它却很媄响性能Q每ơ调用getInstanceҎ(gu)的时候都必须获得Singleton的锁Q而实际上Q当单例实例被创Z后,其后的请求没有必要再使用互斥机制?/p>
3.2 double-checked locking
曄有hZ解决以上问题Q提Zdouble-checked locking的解x?/p>
Java代码 < type="application/x-shockwave-flash" width="14" height="15" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=public%20static%20Singleton%20getInstance()%7B%20%20%20%20%20%20%0A%20%20%20%20if%20(instance%20%3D%3D%20null)%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20synchronized(instance)%7B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20if(instance%20%3D%3D%20null)%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20instance%20%3D%20new%20Singleton()%3B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%0A%20%20%20%20return%20instance%3B%20%20%20%20%20%20%20%0A%7D" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14">
public static Singleton getInstance(){
if (instance == null )
synchronized (instance){
if (instance == null )
instance = new Singleton();
}
return instance;
}
public static Singleton getInstance(){
if (instance == null)
synchronized(instance){
if(instance == null)
instance = new Singleton();
}
return instance;
} 让我们来看一下这个代码是如何工作的:首先当一个线E发求后Q会先检查instance是否为nullQ如果不是则直接q回其内容,q样避免了进?synchronized块所需要花费的资源。其ơ,即ɽW?节提到的情况发生了,两个U程同时q入了第一个if判断Q那么他们也必须按照序执行 synchronized块中的代码,W一个进入代码块的线E会创徏一个新的Singleton实例Q而后l的U程则因为无法通过if判断Q而不会创建多余的实例?/p>
上述描述g已经解决了我们面临的所有问题,但实际上Q从JVM的角度讲Q这些代码仍然可能发生错误?/p>
对于JVM而言Q它执行的是一个个Java指o。在Java指o中创建对象和赋值操作是分开q行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVMq不保证q两个操作的先后序Q也是说有可能JVM会ؓ新的Singleton实例分配I间Q然后直接赋值给instance成员Q然后再d始化q个Singleton实例。这样就使出错成Z可能Q我们仍然以A、B两个U程ZQ?/p>
1. A、BU程同时q入了第一个if判断
2. A首先q入synchronized块,׃instance为nullQ所以它执行instance = new Singleton();
3. ׃JVM内部的优化机ӞJVM先画Z一些分配给Singleton实例的空白内存,q赋值给instance成员Q注意此时JVM没有开始初始化q个实例Q,然后Ad了synchronized块?/p>
4. Bq入synchronized块,׃instance此时不是nullQ因此它马上d了synchronized块ƈ结果返回给调用该方法的E序?/p>
5. 此时BU程打算使用Singleton实例Q却发现它没有被初始化,于是错误发生了?/p>
4 通过内部cd现多U程环境中的单例模式
Z实现慢加载,q且不希望每ơ调用getInstance旉必须互斥执行Q最好ƈ且最方便的解军_法如下:
Java代码 < type="application/x-shockwave-flash" width="14" height="15" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" src="http://xupo.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=public%20class%20Singleton%7B%20%20%20%20%20%20%0A%20%20%20%20private%20Singleton()%7B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%E2%80%A6%20%20%20%20%20%20%0A%20%20%20%20%7D%20%20%20%20%20%20%0A%20%20%20%20private%20static%20class%20SingletonContainer%7B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20private%20static%20Singleton%20instance%20%3D%20new%20Singleton()%3B%20%20%20%20%20%20%0A%20%20%20%20%7D%20%20%20%20%20%20%0A%20%20%20%20public%20static%20Singleton%20getInstance()%7B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20return%20SingletonContainer.instance%3B%20%20%20%20%20%20%0A%20%20%20%20%7D%20%20%20%20%20%20%0A%7D%20%20%20%20%20%0A" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14">
public class Singleton{
private Singleton(){
…
}
private static class SingletonContainer{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonContainer.instance;
}
}
public class Singleton{
private Singleton(){
…
}
private static class SingletonContainer{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonContainer.instance;
}
}
JVM内部的机制能够保证当一个类被加载的时候,q个cȝ加蝲q程是线E互斥的。这样当我们W一ơ调用getInstance的时候,JVM能够帮我们保证instance只被创徏一ơ,q且会保证把赋值给instance的内存初始化完毕Q这h们就不用担心3.2中的问题。此外该Ҏ(gu)也只会在W一ơ调用的时候用互斥机Ӟq样p决了3.1中的低效问题。最后instance是在W一ơ加载SingletonContainercL被创建的Q?SingletonContainercd在调用getInstanceҎ(gu)的时候才会被加蝲Q因此也实现了惰性加载?/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/fancyerII/archive/2010/03/15/5382349.aspx