多线程安全修改全局变量

在多线程环境中,通过静态变量count进行车票售卖时,出现了负数问题。分析表明,即使使用`synchronized`同步块,线程仍可能在判断`count>0`时使用的是旧的副本,导致负数。解决方案是在同步块内再次进行判断以确保线程安全。此外,讨论了多线程共享变量的同步问题,强调了每次读取变量时应获取最新的内存内容。最后,提到了单例模式的线程安全实现。
摘要由CSDN通过智能技术生成

一步一步分析问题先看下面

1.当我开1000个线程出售1000张票时,数据正常,但是当我开1100个时就会出现负数?为什么啊?明明已经加了判断

count>0

public class C{
    int count=1000;//火车票
	static long currenttime;
	static long endtime;
	static File file=new File("C:/Users/绝影/Desktop/log.txt");
	static OutputStream out=null;
	static OutputStreamWriter output=null;
	static {
		
		System.out.println("我是静态块");
		try {
		 out=new FileOutputStream(file);
		 output=new OutputStreamWriter(out);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	

 public  void one() throws IOException {      
	        // TODO 线程输出方法    
	        	try {
	        		if(count>0) {
	        			synchronized(this) {
	        					output.write("车票"+(count--)+"正在      "+Thread.currentThread().getName()+"   出售"+"\r\n");
		    					System.out.println("车票"+(count)+"正在      "+Thread.currentThread().getName()+"   出售"+"\r\n");
	        			}
	        		}else{
	        			endtime=System.currentTimeMillis();
	        			System.out.println(endtime);
	        			System.out.println("抱歉现在没有车票了"+"总共用了时间"+(endtime-currenttime)+"卖完完余票");	
	        			System.exit(0);
	        		}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally {  
					output.flush();
	        }  
		
	}
 
 

	public static void main(String[] args) throws InterruptedException {
		currenttime=System.currentTimeMillis();
		final C output = new C();  
		final R b = new R();
		final BB e = new BB();
		System.out.println("当前时间"+currenttime);
		
		//方式1
		for(int j=1;j<=1100;j++) {
			 new Thread() {  
		            public void run() {  
		                try {
		                	try {
								sleep(10);
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}//模仿网络延迟
							output.one();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}  
		            };  
		        }.start(); 
		}
	
	}

}
2.分析如下

if(count>0) {
        synchronized(this) {
        output.write("车票"+(count--)+"正在      "+Thread.currentThread().getName()+"   出售"+"\r\n");
    System.out.println("车票"+(count)+"正在      "+Thread.currentThread().getName()+"   出售"+"\r\n");
        }
        }


分析应该是这样的,虽然加了synchronized保证了同一个时刻当出现多个线程抢占时,这时候只有一个线程能进入到synchronized块中,但是对于if(count>0) 判断其它线程还是可以访问。因为我电脑时双核四线程,


双核四线程是每个核心不停地在两个线程之间切换,以达到和四核相似的处理能力,自然同一个时刻可以跑两个线程。
如果我们假设某一时刻内存中的数count是1,执行类似i--操作,比方第1000个线程进行了if(count>0)后运行同步块中的内容,这时候第1001个线程已经拷贝了之前内存中变量1的副本进行了if(count>0)操作,遇到了 synchronized发现有线程在使用,此时等待,当第1000个线程执行完同步副本变量到内存时,此时count=0,然后第1001个线程已经用之前的变量副本1进行了count>0的判断,所以还是进入了同步块,自然就出现了负数问题。为了验证假设当我在同步快中再次执行if(count>0)操作后在操作变量后,count不在出现负数,说明假设成立,也说明我们线程在使用到变量时,每次都会去读取当前内存中的当前变量内容。多线程不同步出现线程共享变量安全是因为每次读取的内存中内容不是最新更新的一个才导致。
其实单核多线程我觉得也会出现,当第1000个执行了if(count>0)的判断后让出了cpu,切换到了第1001个执行,第1001个执行完判断并且执行完同步块中的内容更新内存中的count为0,但是第1000个线程已经执行过if(count>0),所以不会再执行这个判断,会接着往后执行,所以如果同步块中不加判断还是会出现负数,这个有点类似于单例模式的这种模型,为了在多线程下保证单例

    • 0
      点赞
    • 7
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值