静态成员变量并发情况下,synchronized关于静态成员变量加锁问题的一次排查

最近看了AQS底层的实现,模仿着写了一个简单的AQS锁,本来想怒装一B,结果中间出现各种坑,把经历贴出来。
记录一次踩坑过程
首先,贴出代码如下:

锁代码如下:
public class TestMyAQSLock{
	private SimpleSync simpleSync = new SimpleSync ();
	
	public void lock(){
		simpleSync.lock(1); 
	}

	public void unLock(){
		simpleSync.tryRelease(0);
	}

	private static final class SimpleSync extends AbstractQueuedSynchronized{
		
		@Override
		protected boolean tryAcqurie(int arg){
			return compareAndSetState(0,arg);
		}
		
		@Override
		protected boolean tryRelease(int arg){
			setState(arg);
			return true;
		}
				
		@Override		
		protected boolean isHeldExclusively(){
			return getState() == 1;
		}		
	}

}

测试代码如下:

public class TestForMyAQSLock{
	public static void main(String[] args){
		ThreadPoolExecutor threadPoolExecutor  = new ThreadPoolExecutor (
			5101L,TimeUnit.SECONDS, new ArrayBlockingQueue<>(100),
			new ThreadPoolExecutor.CallerRunPolicy() );
		for(int i=0; i<100; i++){
			Singer singer = new Singer();
			threadPoolExecutor.execute(singer);
		}
		threadPoolExecutor.shutdown();
	}
	
	static class Singer extends Thread{
		TestMyAQSLock testMyAQSLock = new TestMyAQSLock();
		private static volatile int num = 1;
		public Singer(){}
		@Override
		public void run(){
			testMyAQSLock.lock(); 
			System.out.println("编号"+num+"歌手在唱歌")
			num++;
			testMyAQSLock.unLock();
		}
	}
}

打印结果如下:
编号3歌手在唱歌.
编号3歌手在唱歌
编号10歌手在唱歌
编号27歌手在唱歌
编号8歌手在唱歌

编号100歌手在唱歌
编号100歌手在唱歌

第一次写多线程的我满脸问号难道是写的锁有问题,决定换成synchronized锁排查一下
修改代码如下:

static class Singer extends Thread{
	private static volatile int num = 1;
	public Singer(){}
	@Override
	public void run(){
		synchronized(Thread.currentThread()){
			System.out.println("编号"+num+"歌手在唱歌")
			num++;
		}
	}
}

并没有任何效果,心态崩了。没办法,第一次写线程代码还是要排查下去
仔细分析代码,先分析为什么加的synchronize好像没有起作用。经过仔细分析
原来问题出现在这里

 for(int i=0; i<100; i++){
			Singer singer = new Singer();
			threadPoolExecutor.execute(singer);
}

这部分代码线程不安全,每一个线程singer执行start的时候,循环并不终止,所以会导致多个线程去执行num++
虽然我对每一个线程内部执行了同步锁,但是并不能保证多线程情况下的安全。
根本原因在于锁的对象加错了。
num为静态成员变量,属于全体对象所有,若想多线程情况下保证操作安全,需要将该类加锁,而不是类对象加锁。
修改后代码如下:

static class Singer extends Thread{
	private static volatile int num = 1;
	public Singer(){}
	@Override
	public void run(){
		synchronized((Singer.class)){
			System.out.println("编号"+num+"歌手在唱歌")
			num++;
		}
	}
}

打印结果如下:
编号3歌手在唱歌.
编号2歌手在唱歌
编号4歌手在唱歌
编号1歌手在唱歌
编号5歌手在唱歌

编号99歌手在唱歌
编号100歌手在唱歌

bingo。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值