springboot中使用timer,即多线程,给变量赋值的几个注意点

最近在springboot中需要用到定时器,永不停歇那种,timer,其实就是新增加一条线程,然后我还想往线程里传入变量,然后我还想在线程里改变变量的值。这个是很危险的动作,琢磨了一下这个java的多线程,做一下记录。

一、错误示范

1、当你在函数中定义一个变量,想要在后面生成的定时器中传入值。如果你像这样传入:

	@RequestMapping(value = "/test")
	@ResponseBody
	public void test(HttpServletRequest request,HttpSession session){
		String test="";
		Timer timer=new Timer();
		timer.schedule(new TimerTask() {
            	public void run() {
            		test="another value";
            	}
	}

这是一定会报这样的错的:

Local variable test defined in an enclosing scope must be final or effectively final

原因很简单,就是告诉你只有传入线程的值只能是final属性。
2、然后,你就开始改啊改:

	@RequestMapping(value = "/test")
	@ResponseBody
	public void test(HttpServletRequest request,HttpSession session){
		final String test="";
		Timer timer=new Timer();
		timer.schedule(new TimerTask() {
            	public void run() {
            		test="another value";
            	}
	}

然后,又会出现新的错误:

The final local variable test cannot be assigned, since it is defined in an enclosing type

这句话的意思就是告诉你,因为你定义的值是final,所以是不能被赋值的。现在你心里是不是一万只草泥马奔腾而过。
所以,常规手段是没用的。

二、正解

1、把变量定义在全局上。

	String test="";
	@RequestMapping(value = "/test")
	@ResponseBody
	public void test(HttpServletRequest request,HttpSession session){
		Timer timer=new Timer();
		timer.schedule(new TimerTask() {
            	public void run() {
            		test="another value";
            	}
	}

这个方法可以解决一部分问题,但是不能解决所有问题,就是当多个前端都调用这个test()函数映射时,这就混乱了,变量一会被这个前端改成了这个值,一会又被另一个前端改成了那个值。这个方法只能用在修改一个全局参数的情况下,这个参数是所有前端都需要修改的那种。
2、定义数组传入。
有人问为什么数组传入了线程还能改变,这不是bug吗?不是的,数组其实也有不能改变的属性,这个属性我看到有一个网友解释说是,数组的长度。数组的长度是不能改变的。
不过这就方便了我们在函数中定义一个数组传入线程。

	@RequestMapping(value = "/test")
	@ResponseBody
	public void test(HttpServletRequest request,HttpSession session){
		String[] test=new String[1];
		Timer timer=new Timer();
		timer.schedule(new TimerTask() {
            	public void run() {
            		test[0]="another value";
            	}
	}

三、其他需要注意的点

1、不要被那些报错以及网上的只言片语给误导了,往另一个线程传值不需要把变量的属性定义为final,那些报错只是想告诉你,在线程中有些属性不能改变,而不是说要你给变量属性加上final,传值到线程内,跟不是线程内没有任何区别,不一样的,只是赋值,在线程内给线程外的变量赋值需要费一番波折。
2、如果你是从前台传过来的值,又刚好跟我一样习惯用request.getParameter(“xxx”)来取值,那你一定要注意,不要把取值这句话写到了线程里面去,你可以写在线程外面,或者直接用注释取值:
错误示范:

	@RequestMapping(value = "/test")
	@ResponseBody
	public void test(HttpServletRequest request,HttpSession session){
		String[] test=new String[1];
		Timer timer=new Timer();
		timer.schedule(new TimerTask() {
            	public void run() {
            		String mvalue=request.getParameter("value");//在这
            		test[0]="another value";
            	}
	}

正确示范:

	@RequestMapping(value = "/test")
	@ResponseBody
	public void test(HttpServletRequest request,HttpSession session){
		String mvalue=request.getParameter("value");//在这
		String[] test=new String[1];
		Timer timer=new Timer();
		timer.schedule(new TimerTask() {
            	public void run() {
            		test[0]="another value";
            	}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
注意事项: 1、主进程传入的对象或变量不管是不是ref线程内操作传入的引用都会影响主进程的对象或变量,且对象只能是nonvisualobject类型的。 2、基础变量如long等等都不能传引用ref会运行会报错 3、SharedObjectUnregister只是把SharedObjectDirectory的去掉,实际内存不会释放必须destroy 4、主进程不能直接访问线程变量和对象,可以通过处理类私有的办法处理。 5、千万注意释放线程的时候一定要把线程里面的资源释放完,不然百分百卡死。比如一个线程里面有一个timing的计时器,如果不先stop(),直接destroy,百分百卡死。如果连接数据库或者其他接口时千万注意了!!!千万要在uf_stop()(此例子的释放预留方法)里面把所有的资源都释放干净,资源都释放干净,源都释放干净,都释放干净,释放干净,放干净,干净,净…… 大体设计思路: 1、在主进程建立一个“任务信息类”数组,其包含“任务线程类”,一个任务对应一个线程。 2、在主进程建立一个“任务管理类”,负责处理任务信息类。 简单举例: 1、新建1个“任务管理类”,再新建N“任务信息类”,将“任务信息类”赋值完成加入“任务管理类”,并创建一个“任务线程类”,此时线程开始running。 2、“任务线程类”有一个内部timing类,监控自己是否执行完成,会改标志。“任务管理类”也有一个timing监控“任务信息类”和“任务线程类”的情况,把完成的结束。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼月半

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值