一、单例设计模式
单例设计模式作用:确保一个类只有一个对象。场景:计算机中的回收站、任务管理器、Java中的Runtime类等好处:在这些业务场景下,使用单例模式,可以避免浪费内存。
1.1 饿汉式
饿汉式(提前创建对象)把类的构造器私有(保证别人不能new)在类中自己创建一个对象,并赋值到一个变量定义一个静态方法,返回自己创建的这个对象饿汉式单例的特点: 在获取类的对象时,对象已经创建好了。 单例设计模式:单线程下是一个对象,多线程下也是一个对象
java">public class Demo {public static void main(String[] args) {//单线程下,只有一个对象
// User user = User.getUser();
// System.out.println(Thread.currentThread().getName()+":"+user);
// User user1 = User.getUser();
// System.out.println(Thread.currentThread().getName()+":"+user1);
//多线程下,也是一个对象new Thread(new Runnable() {@Overridepublic void run() {User user = User.getUser();System.out.println(Thread.currentThread().getName()+":"+user);}},"A").start();
new Thread(() -> {User user = User.getUser();System.out.println(Thread.currentThread().getName()+":"+user);},"B").start();
}
}
class User{private String name;private Integer age;//2. 创建一个自己的对象private static User user = new User();
// 1. 私有的构造器private User(){}
// 3. 定义一个静态方法,返回user对象public static User getUser(){return user;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
}
1.2 懒汉式
懒汉式(第一次获取时创建对象)把类的构造器私有(保证别人不能new)在类中定义一个类变量用于存储对象(注意:此时只定义,不创建)提供一个类方法,在方法中创建并返回对象(要保证只创建一次) 注意获取方法需要使用synchronized修饰,以保证只有一个线程可以成功创建出对象
java">public class Demo {public static void main(String[] args) {// 单线程
// Teacher teacher1 = Teacher.getTeacher();
// System.out.println(teacher1);
// Teacher teacher2 = Teacher.getTeacher();
// System.out.println(teacher2);
//多线程,不能保证返回的是同一个对象(可以加锁解决该问题)for (int i = 0; i < 100; i++) {new Thread(new Runnable() {@Overridepublic void run() {Teacher teacher1 = Teacher.getTeacher();System.out.println(Thread.currentThread().getName()+":"+teacher1);}}).start();}
// new Thread(new Runnable() {
// @Override
// public void run() {
// Teacher teacher1 = Teacher.getTeacher();
// System.out.println(Thread.currentThread().getName()+":"+teacher1);
// }
// },"t1").start();
//
// new Thread(new Runnable(){
// @Override
// public void run() {
// Teacher teacher2 = Teacher.getTeacher();
// System.out.println(Thread.currentThread().getName()+":"+teacher2);
// }
// },"t2").start();
}
}
class Teacher{private String name;private Integer age;//1. 私有化构造器private Teacher(){}
//2. 定义一个类变量,用于存储对象private static Teacher teacher;
//3. 定义一个静态方法,返回当前类的对象//3.1 同步方法public static synchronized Teacher getTeacher(){if(teacher==null){teacher = new Teacher();}return teacher;}
// //3.2 同步代码块
// public static Teacher getTeacher(){
// if (teacher == null) {
// synchronized (Teacher.class) {
// if (teacher == null) {
// teacher = new Teacher();
// }
// }
// }
// return teacher;
// }}
1.3 枚举实现单例
枚举实现单例直接在枚举中提供一个枚举项就可以实现单例 注意Google首席Java架构师、(Effective Java》 一书作者Java集合框架的开创者Joshua Bloch在Effective Java一书中提到单元素的枚举类型,已经成为实现singleton的最佳方法在这种实现方式中,既可以避免多线程同步问题还可以防止通过反射和反序列化来重新创建新的对象在很多优秀的开源代码中,我们经常可以看到使用枚举方式来实现的单例模式类
java">public class Demo {public static void main(String[] args) {// 单线程
// School school1 = School.ShunYi;
// System.out.println(Thread.currentThread().getName()+"-->"+school1);
// School school2 = School.ShunYi;
// System.out.println(Thread.currentThread().getName()+"-->"+school2);
// 多线程new Thread(()->{School school = School.ShunYi;System.out.println(Thread.currentThread().getName()+":"+school);},"A").start();
new Thread(()->{School school = School.ShunYi;System.out.println(Thread.currentThread().getName()+":"+school);},"B").start();}
}
enum School{ShunYi
}
二、动态代理
java">/*** ClassName:Star* Description:* 明星接口* 唱歌* 跳舞*/
public interface Star {// 唱歌public String sing(String name);// 跳舞void dance();
}
/*** ClassName:Yct* Description:* 明星实现类*/
public class Yct implements Star{@Overridepublic String sing(String name) {System.out.println("Yct开始唱歌,歌名" + name);return name;}
@Overridepublic void dance() {System.out.println("Yct开始跳舞");}
}
/*** ClassName:ProxyUtil* Description:* 创建明星的代理类*/
public class ProxyUtil {//创建明星的代理对象public static Star createProxy(Star star){//1. 获取代理对象对应的类加载器//2. 编写代理类的业务逻辑InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//生成的代理对象,代理的方法,代理方法的参数// 1. 获取方法名(调用代理对象的方法名字)String name = method.getName();// 2. 判断是否是唱歌方法if ("sing".equals(name)){// 3. 执行代理方法System.out.println("经纪人-准备话筒-收钱");}else {System.out.println("经纪人-准备场地-收钱");}Object o = method.invoke(star, args);//调用目标对象的方法return o;}};//3. 生成代理对象Object obj = Proxy.newProxyInstance(//用于指定用哪个类加载器,去加载生成的代理类star.getClass().getClassLoader(),//获取当前类加载器,把类加载到JVM中//用于指定代理类需要实现的接口star.getClass().getInterfaces(),//获取当前类实现的接口,代理有哪些行为//用于指定代理类对应的处理器,处理代理类上的方法调用(用来指定生成的代理对象要干什么事情)invocationHandler);//4. 返回代理对象return (Star) obj;}
}
/*** ClassName:ProxyUtilTest* Description:* 测试类*/
public class ProxyUtilTest {public static void main(String[] args) {//1. 创建明星对象Yct yct = new Yct();//2. 创建代理对象Star proxy = new ProxyUtil().createProxy(yct);
//3. 调用代理对象的方法proxy.dance();proxy.sing("小苹果");}
}
使用代理优化用户管理类
场景某系统有一个用户管理类,包含用户登录,删除用户,查询用户等功能,系统要求统计每个功能的执行耗时情况,以便后期观察程序性能。 需求现在,某个初级程序员已经开发好了该模块,请观察该模块的代码,找出目前存在的问题,并对其进行改造。
java">/*** 用户业务接口*/
public interface UserService {// 登录功能void login(String loginName, String passWord) throws Exception;
// 删除用户void deleteUsers() throws Exception;
// 查询用户,返回数组的形式。String[] selectUsers() throws Exception;
}
/*** 用户业务实现类*/
public class UserServiceImpl implements UserService {@Overridepublic void login(String loginName, String passWord) throws Exception {// long time1 = System.currentTimeMillis();if ("admin".equals(loginName) && "123456".equals(passWord)) {System.out.println("您登录成功,欢迎光临本系统~");} else {System.out.println("您登录失败,用户名或密码错误~");}Thread.sleep(1000);// long time2 = System.currentTimeMillis();// System.out.println("login方法耗时:" + (time2 - time1));}
@Overridepublic void deleteUsers() throws Exception {//long time1 = System.currentTimeMillis();System.out.println("成功删除了1万个用户~");Thread.sleep(1500);//long time2 = System.currentTimeMillis();//System.out.println("deleteUsers方法耗时:" + (time2 - time1));}
@Overridepublic String[] selectUsers() throws Exception {//long time1 = System.currentTimeMillis();System.out.println("查询出了3个用户");String[] names = {"张全蛋", "李二狗", "牛爱花"};Thread.sleep(500);//long time2 = System.currentTimeMillis();//System.out.println("selectUsers方法耗时:" + (time2 - time1));return names;}
}
/*** ClassName:UserServiceProxy* Description:* 生成代理对象* @version 1.0* @Author wang* @Creat 2024/9/13 14:52*/
public class UserServiceProxyUtil {public static UserService createProxy(UserService userService){// 1.获取被代理对象----userService
// 2.创建代理的业务逻辑InvocationHandler invocationHandler = new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 2.1 获取调用代理对象的方法名String methodName = method.getName();if(methodName.equals("login")){System.out.println( new Date() + "--" + Arrays.toString(args) + "登录了");}// 2.2 进行计时开始long begin = System.currentTimeMillis();
// 2.3 调用被代理对象的方法Object o = method.invoke(userService, args);
// 2.4 进行计时结束long end = System.currentTimeMillis();
// 2.5 计算差值long time = end - begin;System.out.println("方法" + methodName + "耗时:" + time + "毫秒");
return o;}};// 3.调用Java的API,生成代理对象UserService userService1 = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), // 类加载器userService.getClass().getInterfaces(), // 接口invocationHandler);// 4.返回代理对象return userService1;}
}
/*** 目标:使用动态代理解决实际问题,并掌握使用代理的好处。*/
public class Test {public static void main(String[] args) throws Exception{// 1、创建用户业务对象UserService userService = new UserServiceImpl();// 2、创建代理对象UserService userServiceProxy = UserServiceProxyUtil.createProxy(userService);
// 2、调用用户业务的功能。userServiceProxy.login("admin", "123456");System.out.println("----------------------------------");
userServiceProxy.deleteUsers();System.out.println("----------------------------------");
String[] names = userServiceProxy.selectUsers();System.out.println("查询到的用户是:" + Arrays.toString(names));System.out.println("----------------------------------");
}
}