多线程synchronized关键字与局部变量,全局变量,静态变量

问题描述:

观察局部变量,全局变量,静态变量在单线程和多线程环境下的不同表现,为多线程编程提供思路。

我们看一个简单例子,它的业务可以理解成售票功能。有一个静态变量记录总票数。

public class MultiThread {
	//我的电脑,这个值为4
    private static final int core = Runtime.getRuntime().availableProcessors();
    //线程池
    ExecutorService es = Executors.newCachedThreadPool();
    
    public void testBooking(){
        ThreadService threadService = new ThreadService();
		
		//线程池新起一个线程
        //里面放入runnable类,该类的run方法是执行订票方法。
        es.submit(()->threadService.bookTicket());
    }

    public static void main(String[] args) {
        MultiThread mt = new MultiThread();
        mt.testBooking();
        mt.es.shutdown();
    }
}

上面定义了一个测试类,testBooking方法里通过线程池创建一个新城,执行订票方法。


public class ThreadService {
   
    //静态变量,总票数
    private static int static_count = 1000;
    //全局变量
    private int out_count = 0;

    public  void  bookTicket(){
        //局部变量
        int count =0;

        //有票可出售,就继续售票
        while (ThreadService.static_count>0){
                if(ThreadService.static_count<=0){
                    break;
                }
                //卖出一张票,全局变量递增
                out_count++;
                //卖出一张票,局部变量递增
                count++;
                //扣除余票
                ThreadService.static_count--;
            try {
                //模拟出票后,售票员跟顾客说两句话,需要花费1毫秒时间
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        if(ThreadService.static_count==0){
            System.out.println("线程:" + Thread.currentThread().getName() + ",卖出了票数:"+ count+", out_count="+out_count);
        }
    }
}

上面的程序调用一个线程运行,其打印结果如下:

线程:pool-1-thread-1,卖出了票数:1000, out_count=1000

可以看到,静态变量被设置成1000,静态变量每次递减1,局部变量和全局变量就每次递增1,而局部变量和全局变量最后的值都是1000,符合我们的预期。

我们把该程序改成多线程运行,但没对它进行同步操作,看看结果是怎样的:


public class MultiThread {
		//我的电脑,这个值为4
    private static final int core = Runtime.getRuntime().availableProcessors();
    //线程池
    ExecutorService es = Executors.newCachedThreadPool();

    public void testBooking(){
        ThreadService threadService = new ThreadService();
        //线程池新起4个线程
        //里面放入runnable类,该类的run方法是执行订票方法。
        es.submit(()->threadService.bookTicket());
        es.submit(()->threadService.bookTicket());
        es.submit(()->threadService.bookTicket());
        es.submit(()->threadService.bookTicket());
    }

    public static void main(String[] args) {
        MultiThread mt = new MultiThread();
        mt.testBooking();
        mt.es.shutdown();
    }
}

而ThreadService类没做任何改变:


public class ThreadService {
    //静态变量,总票数
    private static int static_count = 1000;
    //全局变量
    private int out_count = 0;

    public  void  bookTicket(){
        //局部变量
        int count =0;

        //有票可出售,就继续售票
        while (ThreadService.static_count>0){
        
                if(ThreadService.static_count<=0){
                    break;
                }
                //卖出一张票,全局变量递增
                out_count++;
                //卖出一张票,局部变量递增
                count++;
                //扣除余票
                ThreadService.static_count--;
            try {
                //模拟出票后,售票员跟顾客说两句话,需要花费1毫秒时间
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        if(ThreadService.static_count==0){
            System.out.println("线程:" + Thread.currentThread().getName() + ",卖出了票数:"+ count+", out_count="+out_count);
        }
    }
}

看下运行Main方法,每次运行得到的结果都不相同,
第一次运行的结果:

线程:pool-1-thread-4,卖出了票数:339, out_count=998
线程:pool-1-thread-1,卖出了票数:337, out_count=998
线程:pool-1-thread-2,卖出了票数:344, out_count=998
线程:pool-1-thread-3,卖出了票数:338, out_count=998

第二次运行的结果:

线程:pool-1-thread-4,卖出了票数:300, out_count=998
线程:pool-1-thread-1,卖出了票数:313, out_count=998
线程:pool-1-thread-2,卖出了票数:298, out_count=998
线程:pool-1-thread-3,卖出了票数:299, out_count=998

但相同的是,4个线程卖出去的票数相加都超过了总票数1000,原因在于每个线程拿到的 ThreadService.static_count 变量是过时的,每个线程正对它+1的时候,其他线程已经对它进行了+1操作。

这里我们对这个+1操作进行同步,确保每次获取值并+1是一次原子操作。
MultiThread 类保持4个线程不变,以下是修改后的ThreadService 类:


public class ThreadService {
    static ThreadService instance = new ThreadService();
    //静态变量,总票数
    private static int static_count = 1000;
    //全局变量
    private int out_count = 0;

    public  void  bookTicket(){
        //局部变量
        int count =0;

        //有票可出售,就继续售票
        while (ThreadService.static_count>0){
			//同步块,对给定的实例对象进行加锁,
			//每次线程进入被synchronized包裹的代码段,都会要求请求instance实例的锁。
            synchronized(instance){

                if(ThreadService.static_count<=0){
                    break;
                }
                //卖出一张票,全局变量递增
                out_count++;
                //卖出一张票,局部变量递增
                count++;
                //扣除余票
                ThreadService.static_count--;
            }

            try {
                //模拟出票后,售票员跟顾客说两句话,需要花费1毫秒时间
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        if(ThreadService.static_count==0){
            System.out.println("线程:" + Thread.currentThread().getName() + ",卖出了票数:"+ count+", out_count="+out_count);
        }
    }
}

运行Main方法,得到结果如下:

线程:pool-1-thread-2,卖出了票数:250, out_count=1000
线程:pool-1-thread-1,卖出了票数:253, out_count=1000
线程:pool-1-thread-3,卖出了票数:249, out_count=1000
线程:pool-1-thread-4,卖出了票数:248, out_count=1000

四个线程卖出的票数相加正好是1000,全局变量也是1000.

总结:

1.方法内的局部变量不受多线程影响。
2.使用多线程操作静态变量时,要对静态变量进行原子操作。
3.synchronized关键字包裹的模块尽量小,同步花费的时间就短。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值