单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。 单例模式的要点有三个: 1.某个类只能有一个实例 2.必须自行创建这个实例 3.必须自行向整个系统提供这个实例 单例模式是一种对象创建型模式
实例 某软件公司承接了一个服务器负载均衡(Load Balance)软件的开发工作,该软件运行在一台负载均衡服务器上,可以将并发访问和数据流量分发到服务器集群中的多台设备上进行并发处理,提高了系统的整体处理能力,缩短了响应时间。由于集群中的服务器需要动态删减,且客户端请求需要统一分发,因此需要确保负载均衡器的唯一性,只能有一个负载均衡器来负责服务器的管理和请求的分发,否则将会带来服务器状态的不一致以及请求分配冲突等问题。如何确保负载均衡器的唯一性是该软件成功的关键,试使用单例模式设计服务器负载均衡器。
分析写在注释里
源码:
package class6;
import java.util.*;
//负载均衡器类,充当单例角色
public class LoadBalancer {
/*私有静态成员变量,存在唯一实例,volatile禁止指令重新排序
* 保证所有线程看到这个变量是一致的
*/
private volatile static LoadBalancer instance=null;
//服务器集合
private List serverList=null;
//私有构造函数
private LoadBalancer() {
serverList = new ArrayList();
}
//共有静态成员方法,返回唯一实例
public static LoadBalancer getLoadBalancer() {
/*为什么在进入同步代码块时需要进行进行判空,假如有线程A和线程B,
* 这时线程A先判断instance为null,所以它进入了同步代码块,
* 创建了对象,然后线程B再进来时,它就不必再进入同步代码快了,
* 可以直接返回,也其实也就是懒加载,可以加快执行速度。*/
if(instance ==null) {
synchronized(LoadBalancer.class) {
/*
* 为什么在同步代码块中还要再进行一次判断呢,假如有线程A和线程B,
* 它俩A先调用方法,B紧接着调用,这时A、B在分析2出的判空都是空,所以A进入同步代码块,
* B进行等待,当A进入同步代码块中创建了对象后,A线程释放了锁,这时B再进入,
* 如果这时不加分析3的判空,B又会创建一个实例,这明显不符合规矩。
*/
if(instance ==null) {
instance =new LoadBalancer();
}
}
}
return instance;
}
//增加服务器
public void addServer(String server) {
serverList.add(server);
}
//删除服务器
public void removeServer(String server) {
serverList.remove(server);
}
//使用Random类随机获取服务器
public String getServer() {
Random random =new Random();
int i =random.nextInt(serverList.size());
return (String)serverList.get(i);
}
}
package class6;
public class Client {
public static void main(String[] args) {
//创建4个LoadBalancer对象
LoadBalancer balancer1,balancer2,balancer3,balancer4;
balancer1 = LoadBalancer.getLoadBalancer();
balancer2 = LoadBalancer.getLoadBalancer();
balancer3 = LoadBalancer.getLoadBalancer();
balancer4 = LoadBalancer.getLoadBalancer();
//判断服务器负载均衡器是否相同
if(balancer1==balancer2 && balancer2==balancer3 && balancer3==balancer4) {
System.out.println("服务器负载均衡器具有唯一性!");
}
//增加服务器
balancer1.addServer("Server 1");
balancer1.addServer("Server 2");
balancer1.addServer("Server 3");
balancer1.addServer("Server 4");
//模拟客户端请求的分支,如果输出结果全为同一个server,可以将适当放大
//例如改为“i<100”
for(int i=0;i<10;i++) {
String server =balancer1.getServer();
System.out.println("分发请求至服务器:"+ server);
}
}
}
运行结果: