解决synchronized(key)传入key值相等,却未成功上锁

此为学习笔记。

实现:当传入方法的key值相同时,需要相隔一秒打印,不相同的,第一时间同时打印。

问题:用synchronized(key)锁住打印的代码,key中有两条数据都是"1",预期效果应该是可以相隔一秒打印,但结果却是同时的。先上代码。

public class ThreadTest3 extends Thread{

	private String key; 
	private String value; 
	private TestDo testDo;
	public ThreadTest3(String key ,String key2 , String value) {
		this.key=key+key2;
		this.value = value;
		this.testDo = TestDo.getInstance();
	}
	
	@Override
	public void run() {
		super.run();
		testDo.dome(key, value);
	}
	public static void main(String[] args) {
		ThreadTest3 test1 = new ThreadTest3("1","","1");
		ThreadTest3 test2 = new ThreadTest3("2","","2");
		ThreadTest3 test3 = new ThreadTest3("1","","3");
		ThreadTest3 test4 = new ThreadTest3("3","","4");
		
		test1.start();
		test2.start();
		test3.start();
		test4.start();
	}
	
}
class TestDo{
	private TestDo() {}
	private static TestDo instance = new TestDo();
	public static TestDo getInstance() {
		return instance;
	}
	public void dome(String key , String value) {
		try {
			synchronized(key) {
				Thread.sleep(1000);
				System.out.println(key+":"+value+"-"+System.currentTimeMillis()/1000);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

结果

如图所示,同一秒打印。

问题原因:常量"1"和"1"是同一个对象,下面这行代码就是要用"1"+""的当时产生新的对象,以实现内容没有改变,任然相等(都还以为"1"),但对象却不再是同一个的效果。

验证:当我们将类构造方法中this.key=key+key2;修改为this.key=key;,这个时候输出正确。

由于学习内容是线程,所以上面的验证为的是证明问题原因的正确性。现在我们用线程的方法解决。(以下方法均值修改内部类)

方法一:

解决办法:用List记录每次传入的key是否已存在于list中,若不存在则add(),若存在,则找出之前传入synchronized中的key,保证是同一个对象传入synchronized,达到解决问题的目的。

class TestDo{
	private List<String> keys = new ArrayList<String>();
	
	private TestDo() {}
	private static TestDo instance = new TestDo();
	public static TestDo getInstance() {
		return instance;
	}
	public void dome(String key , String value) {
		String str = key;
		//如果list中不存在此key,则放入list
		if(!keys.contains(str)) {
			keys.add(str);
		}else {//若已存在key,则找出之前传入synchronized中的key,保证是同一个对象,达到解决问题的目的
			for(int i = 0 ; i < keys.size(); i++) {
				if(key.equals(keys.get(i))) {
					str = keys.get(i);
				}
			}
		}
		try {
			synchronized(str) {
				Thread.sleep(1000);//相同的key,打印时间相隔一秒
				System.out.println(key+":"+value+"-"+System.currentTimeMillis()/1000);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

方法二:

解决办法:将for循环换成迭代器,如图

存在问题:遍历时,操作集合会报错,上图。

解决办法:list的实现换成CopyOnWriteArrayList,此时允许遍历集合时,操作集合。

以上,为学习笔记,勿喷。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值