一、概念
单例模式,保证一个类只有一个实例,并提供一个访问它的全局访问点 。
二、基本代码
//单例类
public class Singleton {
private static Singleton singleton;//保存自己的唯一实例
private Singleton(){//不允许外界进行new Singleton()得到实例对象
}
public static Singleton GetInstance(){
if(singleton==null){//如果此时不存在Singleton的实例对象,则初始化一个Singleton实例对象
singleton=new Singleton();
}
return singleton;
}
}
//客户端---单例模式
public class Client {
public static void main(String[] args) {
Singleton singleton1=Singleton.GetInstance();//获得一个Singleton类的实例
Singleton singleton2=Singleton.GetInstance();
if(singleton1==singleton2){
System.out.println("两个对象是相同的实例");
}else{
System.out.println("两个对象不是相同的实例");
}
}
}
三、多线程下的单例模式
上面的基本代码适合于单线程的程序,如果是多线程的程序,也就是说多次同时访问Singleton类,那么就需要给进程加一把锁(lock)来处理。具体如下
//多线程下的单例类
public class Singleton {
private static Singleton singleton;
private final static Object syncRoot=new Object();
private Singleton(){//私有的构造方法
}
public static Singleton GetInstance(){
if(singleton==null){
//synchronized同步块括号中的锁定对象是采用的一个无关的Object类实例,而不是采用this,
//因为getInstance是一个静态方法,在它内部不能使用未静态的或者未实例的类对象
//synchronized (Singleton.class)
synchronized (syncRoot) {//(双重锁定)
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
四、实例之内部子窗体
//子窗口:单例类
public class SubFrame extends JInternalFrame {
private static SubFrame frame;
private SubFrame() {
super("子窗体", true, true, true, false);
this.setLocation(20, 20);
this.setSize(200, 200);
this.addInternalFrameListener(new MyListener());
this.setVisible(true);
}
public static SubFrame getFrame() {
if (frame == null) {
frame = new SubFrame();
}
return frame;
}
/*
* 事件监听器---》子窗口关闭时,设置窗口对象为null
*/
class MyListener extends InternalFrameAdapter {
public void internalFrameClosing(InternalFrameEvent e) {
if (frame != null) {
frame = null;
}
}
}
}
public class Client extends JFrame{
private JButton jButton;
private JDesktopPane desktopPane;
private SubFrame frame=null;
public Client(){
super("主窗体");
Container container=this.getContentPane();
container.setLayout(new BorderLayout());
jButton=new JButton("点击创建一个内部子窗体");
jButton.addActionListener(new BtListener());
container.add(jButton, BorderLayout.SOUTH);
desktopPane=new JDesktopPane();
container.add(desktopPane);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setSize(400,400);
this.show();
}
//按钮监听器--->点击按钮后判断子窗体是否为空,不为空则移除
//否则新添一个子窗体
class BtListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
if(frame!=null){
desktopPane.remove(frame);
}
frame=SubFrame.getFrame();
desktopPane.add(frame);
}
}
public static void main(String[] args) {
new Client();
}
}
结果:
四、总结
1、单例模式可根据实例的创建时间分为懒汉式单例模式和饿汉式单例模式。懒汉式单例模式是指在第一次请求Singleton类时才得到一个实例,而饿汉单例模式是在单例类被加载时就得到一个实例。
private static Singleton singleton;//懒汉
private static Singleton singleton=new Singleton();//饿汉
2、双重锁定。双重锁定是为了不让线程每次都锁定,而只是在实例未被创建时才加锁处理,同时可保证多线程的安全。具体可看上述代码(多线程下的单例模式)的GetInstance部分。
A certain amount of care or pain or trouble is necessary for every man at all times.A ship without ballast is unstable and will not go straight.