(一)设计模式之单例模式(singtonMode)

参考文章:

(1)https://blog.csdn.net/li295214001/article/details/48135939

(2)http://love-love-l.blog.163.com/blog/static/21078304201001804211901/

(3)https://blog.csdn.net/eff666/article/details/67640648

(4)https://blog.csdn.net/jason0539/article/details/23297037

参考图书:

《软件设计模式与体系结构》

概念:

单例模式是值确保一个类仅有一个唯一的实例,并且提供一个全局的访问点!

(一)懒汉式单例:(又分为线程安全的和线程不安全的)

          (1.1) 懒汉式线程不安全的:

public class Sington {

	// 私有化构造器
	private Sington() {
	}

	// 提供一个静态的该类对象
	private static Sington instance = null;

	// 生成该属性的public的方法,以供外界通过这个方法获得该类的实例
	public static Sington getInstance() {
		if(instance == null) {
			//如果当前属性值为null,返回一个新构建的
			instance= new Sington();
		}
		//如果不是那么就不再构建,直接返回已经存在的
		return instance;
	}


	public static void main(String[] args) {
		// 创建两个对象
		Sington s1 = Sington.getInstance();
		Sington s2 = Sington.getInstance();

		// 判断是否为同一个Sington对象,如果结果为true,说明则为单例
		System.out.println(s1 == s2);

	}

}

 结果为true!!

这种方式,大家也看到了,并没有对多线程进行考虑,一旦有多个线程同时请求,那就并不能保证单一性!!

使用上面的方式测试多线程:

public class Sington {

	// 私有化构造器
	private Sington() {
	}

	// 提供一个静态的该类对象
	private static Sington instance = null;

	// 生成该属性的public的方法,以供外界通过这个方法获得该类的实例
	public static Sington getInstance() {
		if(instance == null) {
			//如果当前属性值为null,返回一个新构建的
			instance= new Sington();
		}
		//如果不是那么就不再构建,直接返回已经存在的
		return instance;
	}


	public static void main(String[] args) {
		// 创建两个对象
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sington s1 = Sington.getInstance();
				System.out.println(s1);
			}
		},"t1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sington s2 = Sington.getInstance();
				System.out.println(s2);
			}
		},"t2");

		
		t1.start();
		t2.start();
	}

}

两个输出的对象:不一致

s1 cn.gxm.mode.test.Sington@322c0983
s2 cn.gxm.mode.test.Sington@310b8809

           (1.2)懒汉式线程安全的(分为三种)

                     (1.2.1)java为上面出现的情况提供了一个关键字synchronized来处理上面的情况

接下来,是懒汉式单例的(考虑线程安全的方式)

public class Sington {

	// 私有化构造器
	private Sington() {
	}

	// 提供一个静态的该类对象
	private static Sington instance = null;

	//对该方法加入synchronized关键字,为防止多线程的对象创建
	public static synchronized Sington getInstance() {
		if(instance == null) {
			//如果当前属性值为null,返回一个新构建的
			instance= new Sington();
		}
		//如果不是那么就不再构建,直接返回已经存在的
		return instance;
	}


	public static void main(String[] args) {
		/**
		 * 此时创建的两个对象是利用多线程创建的,但是加上synchronized关键字之后,
		 * 第一个线程在创建的时候,第二个线程是无法进入对象的该方法的!!
		 */
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sington s1 = Sington.getInstance();
				System.out.println(s1);
			}
		},"t1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sington s2 = Sington.getInstance();
				System.out.println(s2);
			}
		},"t2");

		
		t1.start();
		t2.start();
	}

}

结果:

s1 cn.gxm.mode.test.Sington@322c0983
s2 cn.gxm.mode.test.Sington@322c0983

(1.2.2)懒汉式的处理多线程的第二种方式:(双重检查锁)

对于懒汉式的处理多线程的第一种方式,相信大家多看到了,是可以解决多线程的问题,但是,比较的耗费资源,因为每一个线程通过对象调用该对象,都需要排队等待,因为前面有一个线程执行了同步锁!接下来,对上面的方式进行部分的优化,代码我就不贴全部了,只贴改了的部分,其它都一样!

//对该方法加入synchronized关键字,为防止多线程的对象创建
	public static Sington getInstance() {
		
		//如果第二个线程也进来,但是当前对象不为空,那么就可以直接拿走
		//不需要在等到进入后,得知,不为空再拿走!!
		if(instance == null) {
			//只是锁住代码块
			synchronized(Sington.class) {
				//如果当前属性值为null,返回一个新构建的
				instance= new Sington();
			}
		}
		//如果不是那么就不再构建,直接返回已经存在的
		return instance;
	}

(1.2.3)懒汉式的处理多线程的第三种方式:静态内部类

这种方法肯定安全,因为至始至终就一个对象!!

public class Sington {

	// 私有化构造器
	private Sington() {
	}
	
	// 提供一个静态的内部类
	private static class staticInsideClass{
		private static final Sington instance = new Sington();
	}


	//通过静态内部类的fina返回对象实例
	public static Sington getInstance() {
		return staticInsideClass.instance;
	}


	public static void main(String[] args) {
		/**
		 * 此时创建的两个对象是利用多线程创建的,但是加上synchronized关键字之后,
		 * 第一个线程在创建的时候,第二个线程是无法进入对象的该方法的!!
		 */
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sington s1 = Sington.getInstance();
				System.out.println(s1);
			}
		},"t1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sington s2 = Sington.getInstance();
				System.out.println(s2);
			}
		},"t2");

		
		t1.start();
		t2.start();
	}

}

结果:一致!

s1 cn.gxm.mode.test.Sington@14e672aa
s2 cn.gxm.mode.test.Sington@14e672aa

(二)第二种饿汉式单例模式(就是不管你有没有用,我一上来就已经把对象创建好,就那一个对象,用你就拿去!)

public class Sington {

	// 私有化构造器
	private Sington() {
	}
	//一开始就在其类的内部创建好,等用了,就给
	//至始至终就这一个对象
	private final static Sington instace = new Sington();
	
	public static Sington getInstance() {
		return Sington.instace;
	}
	

	public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sington s1 = Sington.getInstance();
				System.out.println(s1);
			}
		},"t1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sington s2 = Sington.getInstance();
				System.out.println(s2);
			}
		},"t2");

		
		t1.start();
		t2.start();
	}

}

结果:一致!

s1 cn.gxm.mode.test.Sington@310b8809
s2 cn.gxm.mode.test.Sington@310b8809

实际使用举例:

Client:

package cn.gxm.mode.test;

import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;

public class Client extends JFrame implements ActionListener{

	private TextArea area = new TextArea("click to get connection");
	private Button connectionButton = new Button("create connection");
	private Button exitButton = new Button("exit"); 
	public Client() {
		super("客户端");
		setBounds(200,300, 400, 400);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());
		
		connectionButton.addActionListener(this);
		exitButton.addActionListener(this);
		
		add(area);
		add(connectionButton);
		add(exitButton);
		
		setVisible(true);
		validate();
		
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == connectionButton) {
			LoginService login = LoginService.getInstance();
			area.setText(login.getMesssage());
		}else if(e.getSource() == exitButton) {
			dispose();
		}
	}
	
	public static void main(String[] args) {
		Client c= new Client();
	}
	
}

LoginService:

package cn.gxm.mode.test;

import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;

public class LoginService extends JFrame {
	
	private TextField username = new TextField("张三");
	private TextField password = new TextField("123456");
	private Button loginButton = new Button("Login");
	private Button exitButton = new Button("exit"); 
	
	//测试是否已经在连接了(默认为false)
	private static boolean isLogin = false;
	
	//告诉客户端请求链接的信息
	public String messsage;
	
	private static LoginService instance = null;
	
	public String getMesssage() {
		return messsage;
	}

	public void setMesssage(String messsage) {
		this.messsage = messsage;
	}



	public static LoginService getInstance() {
		if(instance == null) {
			synchronized (LoginService.class) {
				instance = new LoginService();
			}
		}
		return  instance;
	}
	
	
	
	private LoginService() {
		super("请求网路登陆端");
		setBounds(200,300, 400, 400);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());
		
		loginButton.addActionListener(new MyActionLister());
		exitButton.addActionListener(new MyActionLister());
		
		add(loginButton);
		add(exitButton);
		add(username);
		add(password);
		
		setVisible(true);
		validate();
		
	}
	
	
	class MyActionLister implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent e) {
			if(e.getSource() == loginButton) {
				if(isLogin) {
					//说明已经有connection了,则告诉客户端错误信息
					messsage = "连接已经开启了,请不要重复开启!!";
				}else {
					isLogin = true;
					messsage = "连接开启成功!!";
				}
			}else if(e.getSource() == exitButton) {
				dispose();
				//重置isLogin
				isLogin = false;
			}
		}
	}
	
}

猜你喜欢

转载自blog.csdn.net/qq_38263083/article/details/82781993