享元设计模式 -- 线程的不安全性

原创 2015年07月10日 12:16:56

这篇博客主要分析了下享元模式的线程不安全行,因为网上没找到相关的博客,
享元模式的学习参考:
http://www.cnblogs.com/chenssy/p/3330555.html
http://www.cnblogs.com/rush/archive/2011/10/01/2197785.html


今天看了下享元的设计模式,
概念如下:

所谓享元模式就是运行共享技术有效地支持大量细粒度对象的复用。系统使用少量对象,而且这些都比较相似,状态变化小,可以实现对象的多次复用。

共享模式是支持大量细粒度对象的复用,所以享元模式要求能够共享的对象必须是细粒度对象。

在了解享元模式之前我们先要了解两个概念:内部状态、外部状态。

内部状态:在享元对象内部不随外界环境改变而改变的共享部分。

外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。

由于享元模式区分了内部状态和外部状态,所以我们可以通过设置不同的外部状态使得相同的对象可以具备一些不同的特性,而内部状态设置为相同部分。在我们的程序设计过程中,我们可能会需要大量的细粒度对象来表示对象,如果这些对象除了几个参数不同外其他部分都相同,这个时候我们就可以利用享元模式来大大减少应用程序当中的对象。如何利用享元模式呢?这里我们只需要将他们少部分的不同的部分当做参数移动到类实例的外部去,然后再方法调用的时候将他们传递过来就可以了。这里也就说明了一点:内部状态存储于享元对象内部,而外部状态则应该由客户端来考虑。

可知享元模式为我们节省了很多的内存空间,省去了不必要的内存资源浪费。
在上面的定义中我们看到【内部状态】【外部状态】的定义,此处在高并发的情况应该不是线程安全的,比如,同一时间2个线程获取同一个对象,然后分别赋予不同的外部状态,这个时候就可能出现不安全的因素

抱着这个想法,我对网上的一个典型的享元模式例子做了修改,果然不出所料

代码如下:

  1. 抽象类
package com.gp;

public abstract class Flyweight {
    public abstract void Operation(int extrinsicstates);

    public abstract String getName();

    public abstract void setCount(int count);

    public abstract int getCount();
}
  1. POJO类
package com.gp;

public class ConcreteFlyweight extends Flyweight {

    @Override
    public void Operation(int extrinsicstates) {
        System.out.println("共享的Flyweight : " + extrinsicstates);
    }

    private String name = "zhangsan";
    private int count = 0;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

}
  1. 工厂类
package com.gp;

import java.util.Hashtable;

public class FlywightFactory {
    private Hashtable<String, Flyweight> flyweights = new Hashtable<String, Flyweight>();

    public FlywightFactory() {
        flyweights.put("X", new ConcreteFlyweight());
        flyweights.put("Y", new ConcreteFlyweight());
        flyweights.put("Z", new ConcreteFlyweight());
    }

    public Flyweight GetFlyweight(String key) {
        return ((Flyweight) flyweights.get(key));
    }
}
  1. 主要的类,测试类,测试线程安全的类
package com.gp;

public class FlyweightPattern {
    static FlywightFactory factory = new FlywightFactory();

    public static void main(String[] args) {
        int extrinsicstates = 1;

        Flyweight fx = factory.GetFlyweight("X");
        fx.Operation(extrinsicstates);

        new Thread() {
            public void run() {
                Flyweight fx = factory.GetFlyweight("X");
                fx.setCount(1);
                System.out.println("1:name=" + fx.getName() + ",count"
                        + fx.getCount());
            }
        }.start();
        new Thread() {
            public void run() {
                Flyweight fx = factory.GetFlyweight("X");
                fx.setCount(2);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("2:name=" + fx.getName() + ",count"
                        + fx.getCount());
            }
        }.start();
        new Thread() {
            public void run() {
                Flyweight fx = factory.GetFlyweight("X");
                fx.setCount(3);
                System.out.println("3:name=" + fx.getName() + ",count"
                        + fx.getCount());
            }
        }.start();
    }
}

输出结果

共享的Flyweight : 1
1:name=zhangsan,count1
3:name=zhangsan,count3
2:name=zhangsan,count3

此时此刻,我们发现了,第二个线程,对象信息被第三个线程改变了。

所以在使用享元模式的时候要当心线程的安全性

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

设计模式学习笔记——享元模式

定义: 使用共享对象可以有效的支持大量的细粒度的对象。 这里出现两个名词:共享对象和细粒度对象,所谓共享对象,这个好说,就是这个对象是常驻在内存中的,供大家一起使用,细粒度对象是说对象很多...

【GOF23设计模式】_享元模式_享元池_内部状态_外部状态_线程池_连接池JAVA242

来源:http://www.bjsxt.com/ 一、S03E242_01【GOF23设计模式】享元模式、享元池、内部状态、外部状态、线程池、连接池package com.test.flyweigh...

排序算法一(冒泡排序、选择排序、插入排序)

一、冒泡排序:     1、算法思想:         对要排序的数据,从上到下依次比较两个相邻的数并加以调整,将最大的数向下移动,较小的数向上冒起。即:每一趟依次比较相邻的两个数据元素,将较小的...

98. Spring Boot启动流程分析第二篇

在上一节博客当中,我们从启动类SpringApplicatio.run()方法分析了一下Spring Boot的启动流程,这节博客我们从另外一个角度分析下。        在spring boot里...

懒汉式单例设计模式线程不安全

懒汉式:延迟加载方式。(先不new,等用到的时候再进行实例化)单例设计模式点击查看 [java] view plain copy   class single2{        ...

线程,设计模式

线程,设计模式

黑马程序员_09. api-线程、单例设计模式

黑马程序员_api-线程及单例设计模式 a.明确以下概念: 1.进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或叫一个控制单元。 2.线程:就是进程中的一个独立的...

JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是cl...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:享元设计模式 -- 线程的不安全性
举报原因:
原因补充:

(最多只允许输入30个字)