单例模式(多例,线程安全)
2015-09-12 20:09
435 查看
单例模式的本质是控制实例的个数,例如限制代码中的实例个数为确定的n个,一般情况下为1个。看代码:
这种属于“饱汉式”的单例模式,不管你什么时候调用,当加载这个类的时候,就初始化了该类的唯一对象。这种写法是线程安全的。在下面的这种情况下,JVM隐含的为您执行的同步。
1 由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时
2 访问final字段时
这种写法属于“饿汉式”的单例模式,只有当需要的时候才去创建。当然,上述代码不是线程安全的。(既不是静态字段,也不是static{}字段),下面给出线程安全的代码:(用synchronized锁住ConnectionManager,表明一个时刻只能有一个线程访问ConnectionManager这个类 ,volatile修饰manager表明当manager被其他线程修改了,所有的线程都可以看到)
下面将给出一个多例模式。
当然,上述代码也不是线程安全的。具体的修改方式就留给大家来改吧。下面将给出一段强大的代码。该代码用于模拟数据库连接。比如假设有5个数据库连接,但是同时可能有8个人来获取连接。获取到连接的人,进行自己的业务操作,没获取到连接的人,则等待直到有人释放了连接,然后获取连接,处理自己的业务。
运行结果如下所示:
class ConnectionManager { private static ConnectionManager manager = new ConnectionManager(); private ConnectionManager() { } public static ConnectionManager getInstance() { return manager; } }
这种属于“饱汉式”的单例模式,不管你什么时候调用,当加载这个类的时候,就初始化了该类的唯一对象。这种写法是线程安全的。在下面的这种情况下,JVM隐含的为您执行的同步。
1 由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时
2 访问final字段时
class ConnectionManager { private static ConnectionManager manager = null; private ConnectionManager() { } public static ConnectionManager getInstance() { if(manager==null){ manager = new ConnectionManager(); } return manager; } }
这种写法属于“饿汉式”的单例模式,只有当需要的时候才去创建。当然,上述代码不是线程安全的。(既不是静态字段,也不是static{}字段),下面给出线程安全的代码:(用synchronized锁住ConnectionManager,表明一个时刻只能有一个线程访问ConnectionManager这个类 ,volatile修饰manager表明当manager被其他线程修改了,所有的线程都可以看到)
class ConnectionManager { private volatile static ConnectionManager manager = null; private ConnectionManager() { } public static ConnectionManager getInstance() { if(manager==null){ synchronized(ConnectionManager.class){ if(manager==null) manager = new ConnectionManager(); } } return manager; } }
下面将给出一个多例模式。
package com.guo.task; /** * 显示如何扩展单例模式,控制单例的个数为3个 * @author guo */ public class OneExtend{ //定义一个缺省的key值的前缀 private final static String DEFAULT_PREKEY="Cache"; //定义缓存实例的容器 private static Map<String,OneExtend> map=new HashMap<String,OneExtend>(); //用来记录当前正在使用第几个实例,到了控制的最大输入,就返回从1开始 private static int num=1; //定义最大的实例的数目 private final static int NUM_MAX=3; public static OneExtend getInstance(){ String key=DEFAULT_PREKEY+num; OneExtend oneExtend=map.get(key); if(oneExtend==null){ oneExtend =new OneExtend(); map.put(key,oneExtend); } //把当前的实例序号加1 num++; if(num>NUM_MAX){ num=1; } return oneExtend; } }
当然,上述代码也不是线程安全的。具体的修改方式就留给大家来改吧。下面将给出一段强大的代码。该代码用于模拟数据库连接。比如假设有5个数据库连接,但是同时可能有8个人来获取连接。获取到连接的人,进行自己的业务操作,没获取到连接的人,则等待直到有人释放了连接,然后获取连接,处理自己的业务。
package com.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MultiModle { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ExecutorService exec = Executors.newCachedThreadPool(); Runnable runnable = new Runnable() { public void run() { try { Connection con = ConnectionManager.getInstance() .getConnection(); System.out.println(Thread.currentThread().getId() + "获取到连接.." + con); System.out.println("使用连接中.."); Thread.sleep(1000);//模拟业务操作 ConnectionManager.getInstance().releaseConnection(con); System.out.println(Thread.currentThread().getId() + "使用结束,释放连接" + con); } catch (InterruptedException e) { e.printStackTrace(); } catch (NotFoundException e) { e.printStackTrace(); } } }; for (int i = 0; i < 8; i++) { exec.execute(runnable); } exec.shutdown(); } } class NotFoundException extends Exception { public NotFoundException() { super("the connection is not founded."); } } class Connection { boolean isUsed; private int id; public Connection(int id) { this.id = id; } public String toString() { return id + "号连接"; } } class ConnectionManager { private static ConnectionManager manager = new ConnectionManager(); private int num = 5; private List<Connection> list; private ConnectionManager() { list = new ArrayList<Connection>(); for (int i = 0; i < num; i++) { list.add( new Connection(i)); } } public static ConnectionManager getInstance() { return manager; } public synchronized Connection getConnection() throws InterruptedException { Connection con = null; while (con == null) { for (int i = 0; i < num; i++) { if (!list.get(i).isUsed) { con = list.get(i); con.isUsed=true; break; } } if (con == null) { System.out.println(Thread.currentThread().getId() + "号线程正在等待..."); wait(); } } return con; } public synchronized void releaseConnection(Connection con) throws NotFoundException { for (int i = 0; i < num; i++) { if (list.get(i) == con) { con.isUsed = false; notifyAll(); return; } } throw new NotFoundException(); } }
运行结果如下所示:
10获取到连接..0号连接 使用连接中.. 13获取到连接..1号连接 使用连接中.. 16获取到连接..2号连接 使用连接中.. 12获取到连接..4号连接 使用连接中.. 11号线程正在等待... 15获取到连接..3号连接 使用连接中.. 17号线程正在等待... 14号线程正在等待... 10使用结束,释放连接0号连接 12使用结束,释放连接4号连接 15使用结束,释放连接3号连接 16使用结束,释放连接2号连接 14获取到连接..0号连接 使用连接中.. 13使用结束,释放连接1号连接 17获取到连接..1号连接 使用连接中.. 11获取到连接..2号连接 使用连接中.. 11使用结束,释放连接2号连接 14使用结束,释放连接0号连接 17使用结束,释放连接1号连接
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统