主线程传递局部变量给子线程,如何保证在高并发情况下,子线程得到的变量不会被其它线程修改?

Summer-t 2020-01-18 04:39:41


这是一个aop记录系统用户操作日志的功能,我想使用异步去记录操作日志,不占用主线程的执行时间,
但经过测试,高并发下,前后得到的url不一致,
请问有什么办法解决吗?
...全文
1531 33 打赏 收藏 转发到动态 举报
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
kingarden 2020-01-21
  • 打赏
  • 举报
回复
使用同步锁来保证值的准确性,不好就是性能会下降。
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 8 楼 rumlee的回复:
感觉是题主自己的测试方法不正确,不管怎么样,一个String对象传入一个新的线程之后,主线程不管怎么修改都影响不了子线程,同样的,子线程不管怎么修改也影响不了主线程。
因为类是单例的,多个线程共用同一个副本,当某主线程的子线程还没执行完时,就有其它线程修改了参数,这不单单是String,就算String不会变,其它的对象参数呢,对吧
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 7 楼 maradona1984的回复:
是不是你看错了,这个url除非你这个方法里修改了指向,就不可能变化. 完全不符合常理,你在别的方法里修改url指向的对象也不会影响原来方法url变量的,具体参考java参数传递
因为子线程还没执行完,又有主线程改变了url的值
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 6 楼 byds520的回复:
使用 ThreadLocal吧
不行的,会存的是主线程的数据
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 26 楼 maradona1984的回复:
[quote=引用 23 楼 qq_28509855 的回复:] [quote=引用 22 楼 maradona1984的回复:][quote=引用 14 楼 qq_28509855 的回复:] [quote=引用 7 楼 maradona1984的回复:]是不是你看错了,这个url除非你这个方法里修改了指向,就不可能变化. 完全不符合常理,你在别的方法里修改url指向的对象也不会影响原来方法url变量的,具体参考java参数传递
因为子线程还没执行完,又有主线程改变了url的值[/quote] 按照你的说法,你传递的所有参数都有可能变了...你觉得可能吗? 这不符合常理的好吧,首先你的url是个局部变量,不同线程拥有各自的线程栈,每个线程就操作各自的局部变量,怎么会有线程安全问题? 先了解下java的内存模型再去了解java的多线程,不然你根本没法正确分析多线程问题[/quote] 那假设调用方法的类和执行方法的类都是单例的呢,有没有可能出现这种情况[/quote] 所以说让你先了解java内存模型,不然空中楼阁,讲不清的,不同线程执行一个方法时,方法区的信息都是进入各自的栈的,局部变量不存在线程安全问题,而且作为参数传递到另外一个方法,形参都是copy变量本身传递到方法里的,传递完成之后修改变量的指向对象都不会影响传递之前/传递之后的,所以你的理解有两个问题,一个是不存在线程安全,二是修改变量的指向对象,并不会影响接收参数的方法内参数指向的对象. 当然我觉得你不一定能正确理解我说的话,所以还是多看书,然后实践几把来映证自己的理解[/quote] 对的,现在经验太少了,书不读,b猛装,才导致这些个尴尬的问题,感谢老哥的解答,谢谢~
xiaozhao127 2020-01-20
  • 打赏
  • 举报
回复
你在主线程做个判断,子线程有没有执行完毕,执行完了在执行子线程就好了。
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 21 楼 ITjavaman的回复:
按你上面的代码,我是不太明白,就这么调用,同一个子线程内打印的两个url会变?

	public static void main(String []args) {
		for(int i=0;i<10;i++) {
			String url = "url"+i;
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					print(url);
					
				}
			}).start();
		}
	}
	
	
	public static void print(String url) {
		System.out.println(Thread.currentThread().getName() +"------start-------->"+url);
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() +"--------end------>"+url);
	}
可能是我的测试方法不对,我等下再重新测试一遍,谢谢~
maradona1984 2020-01-20
  • 打赏
  • 举报
回复
引用 23 楼 qq_28509855 的回复:
[quote=引用 22 楼 maradona1984的回复:][quote=引用 14 楼 qq_28509855 的回复:] [quote=引用 7 楼 maradona1984的回复:]是不是你看错了,这个url除非你这个方法里修改了指向,就不可能变化. 完全不符合常理,你在别的方法里修改url指向的对象也不会影响原来方法url变量的,具体参考java参数传递
因为子线程还没执行完,又有主线程改变了url的值[/quote] 按照你的说法,你传递的所有参数都有可能变了...你觉得可能吗? 这不符合常理的好吧,首先你的url是个局部变量,不同线程拥有各自的线程栈,每个线程就操作各自的局部变量,怎么会有线程安全问题? 先了解下java的内存模型再去了解java的多线程,不然你根本没法正确分析多线程问题[/quote] 那假设调用方法的类和执行方法的类都是单例的呢,有没有可能出现这种情况[/quote] 所以说让你先了解java内存模型,不然空中楼阁,讲不清的,不同线程执行一个方法时,方法区的信息都是进入各自的栈的,局部变量不存在线程安全问题,而且作为参数传递到另外一个方法,形参都是copy变量本身传递到方法里的,传递完成之后修改变量的指向对象都不会影响传递之前/传递之后的,所以你的理解有两个问题,一个是不存在线程安全,二是修改变量的指向对象,并不会影响接收参数的方法内参数指向的对象. 当然我觉得你不一定能正确理解我说的话,所以还是多看书,然后实践几把来映证自己的理解
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 24 楼 ITjavaman的回复:
[quote=引用 23 楼 qq_28509855 的回复:] [quote=引用 22 楼 maradona1984的回复:][quote=引用 14 楼 qq_28509855 的回复:] [quote=引用 7 楼 maradona1984的回复:]是不是你看错了,这个url除非你这个方法里修改了指向,就不可能变化. 完全不符合常理,你在别的方法里修改url指向的对象也不会影响原来方法url变量的,具体参考java参数传递
因为子线程还没执行完,又有主线程改变了url的值[/quote] 按照你的说法,你传递的所有参数都有可能变了...你觉得可能吗? 这不符合常理的好吧,首先你的url是个局部变量,不同线程拥有各自的线程栈,每个线程就操作各自的局部变量,怎么会有线程安全问题? 先了解下java的内存模型再去了解java的多线程,不然你根本没法正确分析多线程问题[/quote] 那假设调用方法的类和执行方法的类都是单例的呢,有没有可能出现这种情况[/quote] 单例也不会,单例只是在内存里只存在一个实例,CPU执行方法时,方法入机栈的时候,参数都会变成局部变量入栈[/quote] 等下我再测试下这种情况,可能是我没测试正确,谢谢~
ITjavaman 2020-01-20
  • 打赏
  • 举报
回复
引用 23 楼 qq_28509855 的回复:
[quote=引用 22 楼 maradona1984的回复:][quote=引用 14 楼 qq_28509855 的回复:] [quote=引用 7 楼 maradona1984的回复:]是不是你看错了,这个url除非你这个方法里修改了指向,就不可能变化. 完全不符合常理,你在别的方法里修改url指向的对象也不会影响原来方法url变量的,具体参考java参数传递
因为子线程还没执行完,又有主线程改变了url的值[/quote] 按照你的说法,你传递的所有参数都有可能变了...你觉得可能吗? 这不符合常理的好吧,首先你的url是个局部变量,不同线程拥有各自的线程栈,每个线程就操作各自的局部变量,怎么会有线程安全问题? 先了解下java的内存模型再去了解java的多线程,不然你根本没法正确分析多线程问题[/quote] 那假设调用方法的类和执行方法的类都是单例的呢,有没有可能出现这种情况[/quote] 单例也不会,单例只是在内存里只存在一个实例,CPU执行方法时,方法入机栈的时候,参数都会变成局部变量入栈
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 22 楼 maradona1984的回复:
[quote=引用 14 楼 qq_28509855 的回复:] [quote=引用 7 楼 maradona1984的回复:]是不是你看错了,这个url除非你这个方法里修改了指向,就不可能变化. 完全不符合常理,你在别的方法里修改url指向的对象也不会影响原来方法url变量的,具体参考java参数传递
因为子线程还没执行完,又有主线程改变了url的值[/quote] 按照你的说法,你传递的所有参数都有可能变了...你觉得可能吗? 这不符合常理的好吧,首先你的url是个局部变量,不同线程拥有各自的线程栈,每个线程就操作各自的局部变量,怎么会有线程安全问题? 先了解下java的内存模型再去了解java的多线程,不然你根本没法正确分析多线程问题[/quote] 那假设调用方法的类和执行方法的类都是单例的呢,有没有可能出现这种情况
maradona1984 2020-01-20
  • 打赏
  • 举报
回复
引用 14 楼 qq_28509855 的回复:
[quote=引用 7 楼 maradona1984的回复:]是不是你看错了,这个url除非你这个方法里修改了指向,就不可能变化. 完全不符合常理,你在别的方法里修改url指向的对象也不会影响原来方法url变量的,具体参考java参数传递
因为子线程还没执行完,又有主线程改变了url的值[/quote] 按照你的说法,你传递的所有参数都有可能变了...你觉得可能吗? 这不符合常理的好吧,首先你的url是个局部变量,不同线程拥有各自的线程栈,每个线程就操作各自的局部变量,怎么会有线程安全问题? 先了解下java的内存模型再去了解java的多线程,不然你根本没法正确分析多线程问题
ITjavaman 2020-01-20
  • 打赏
  • 举报
回复
按你上面的代码,我是不太明白,就这么调用,同一个子线程内打印的两个url会变?

	public static void main(String []args) {
		for(int i=0;i<10;i++) {
			String url = "url"+i;
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					print(url);
					
				}
			}).start();
		}
	}
	
	
	public static void print(String url) {
		System.out.println(Thread.currentThread().getName() +"------start-------->"+url);
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() +"--------end------>"+url);
	}
weixin_46213818 2020-01-20
  • 打赏
  • 举报
回复
tonggan
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 17 楼 惊喜不断的回复:
这问题问的,,,,,主线程局部变量 ,还不想让子线程修改 ,设置为局部常量就可以了呗, 还有什么难度吗?? 还是我理解有问题?
子线程没有修改哦,只是一个放入实体类的动作,而且不能是常量,它是一个变动的值
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 16 楼 幻风的回复:
不用锁,又用单例,这种方式当然会出现这情况,要变一下思路,要么url修改放主线程,要么共享一个url数据池,单独一个子线程添加url,其他子线程只读
url是在主线程进行的赋值,然后再传入异步方法中,单例是spring注解默认方式,加锁的话我可以试试,看看耗时大不大,谢谢大兄弟
惊喜不断 2020-01-20
  • 打赏
  • 举报
回复
这问题问的,,,,,主线程局部变量 ,还不想让子线程修改 ,设置为局部常量就可以了呗, 还有什么难度吗?? 还是我理解有问题?
幻风 2020-01-20
  • 打赏
  • 举报
回复
不用锁,又用单例,这种方式当然会出现这情况,要变一下思路,要么url修改放主线程,要么共享一个url数据池,单独一个子线程添加url,其他子线程只读
Summer-t 2020-01-20
  • 打赏
  • 举报
回复
引用 32 楼 山顶上的飞机的回复:
使用ThreadLocal来解决: private ThreadLocal<String> threadLocal=new ThreadLocal<>(); 获取到url后threadLocal.set(url); 在下边要使用的时候threadLocal.get()
试过哦,你存的是主线程的,子线程是取不到的
山顶上的飞机 2020-01-20
  • 打赏
  • 举报
回复
使用ThreadLocal来解决: private ThreadLocal<String> threadLocal=new ThreadLocal<>(); 获取到url后threadLocal.set(url); 在下边要使用的时候threadLocal.get()
加载更多回复(13)

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧