单例和多实例(@Scope("prototype"))的区别
/*当前controller类在ioc中默认是单例的,类中有成员变量name,第一个请求http://localhost:8080/testScope/aaa过来后,从ioc中拿出这个类的
单例对象,name赋值为aaa,并持续输出,这事第二个请求http://localhost:8080/testScope/bbb过来后,从ioc中取出的类对象还是同一个,
给name赋值bbb,两个请求同时输出,这时第一个请求的输出name也变成了bbb,for循环中的变量i值还是各自的.加上@Scope("prototype")
变成多例后,第二个请求不影响第一个请求的name值,因为第二个请求用的是新的实例对象.如果直接输出方法参数中的username,多个请求之间的username也不会
相互影响.也就是方法的参数变量和方法内定义的变量都是不受影响的.这个例子也说明了多个请求使用同一个单例对象,前面的请求没处理完不会阻塞
后面的请求,也就是说多个请求线程使用同一个单例是可以的,只要考虑好线程安全问题就可以,如果把属性name定义在方法内部,单例模式下多个线程修改name值也不会相互影响*/
package kun.concurrent; import org.springframework.context.annotation.Scope; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/testScope") @Scope("prototype") public class TestScope { private String name; @RequestMapping(value = "/{username}",method = RequestMethod.GET) public void userProfile(@PathVariable("username") String username) { name = username; try { for(int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getId() + "name"+i+":" + name); Thread.sleep(2000); } } catch (Exception e) { e.printStackTrace(); } return; }
大多数业务都使用singleton单实例,因此spring也默认的类型也是singleton,singleton保证了全局是一个实例,对性能有所提高,但是如果实例中有非静态变量时,可能会导致线程安全、共享资源的竞争等问题。
当设置为prototype(多实例)时:每次连接请求,都会重新生成一个新的bean实例,这也会导致一个问题,当请求数越多,性能会降低,因为频繁创建的新的实例,会导致GC频繁,GC回收时长增加。要根据实际情况选择哪一种方式
单例模式线程安全吗?
单例线程不安全,在 单例Bean 中尽量避免定义可变的成员变量。推荐的做法时在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中。
不过,大部分 Bean 实际都是无状态(没有实例变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理