一文让你了解Java的可见性与原子性

多线程是java里比较复杂的一个技术,多线程有2个重要的概念:可见性与原子性。

因为线程是有缓存的,它里面对象的值可能会与主存里的不一样。这样就会导致一个问题:线程用的不是最新的值,从而导致错误。

可见性是指同一个对象在不同的线程之间表现一致,具有相同的值。怎么实现可见性呢?线程在读一个变量的时候,先去主存把值同步过来,在写一个变量的时候,把新值同步到主存,这样可以保证各个线程用的都是最新的值。

一个i++的简单语句,在我们看来已经不能再拆分了,但在虚拟机字节码层面却不是这样,这样一个简单的java语句会被拆分成3个操作,先取值,再加1,再存值。线程有可能在取值完,还没加1的时候,时间片就用完了,被置换出CPU,等待下一个时间片。

原子性就是说我们要保证一系列的指令要么不执行,要么一次执行完。如果不保证原子性,会有什么问题呢?不保证原子性就保证不了可见性。假设我们有多个线程同时让一个变量自增,当某一个线程自增的指令没有执行完时间片就耗尽了,这时它就不会去更新主存里的值,当另一个线程运行时,它拿到的还是老的值,这时错误就发生了。Java提供了AtomicInteger等类用来保证原子性。

如果我们有一个变量是多个线程同时读写的,如何保证它是线程安全的呢?

1、可以用synchronized关键字来修饰所有的读写方法,synchronized关键字既可以保证原子性,又可以保证可见性。像Java的Vector类和HashTable都是这么做的。

2、可以用volatile和AtomicXXX来实现,volatile用来保证可见性,AtomicXXX类保证了原子性。

接下来,一个经典的多线程累加让你看看效果:

import java.util.concurrent.atomic.AtomicInteger;

public class Main {

    public static void main(String[] args) {
        new Test().start();
    }

    public static class Test {
        private int a = 0;
        private volatile int b = 0;
        private int c = 0;
        private volatile AtomicInteger d = new AtomicInteger(0);

        public void start() {
            for (int i = 0; i < 10; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int j = 0; j < 1000; j++) {
                            a++;
                            b++;
                            plus();
                            d.incrementAndGet();
                        }
                    }
                }).start();
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("a = " + a);
            System.out.println("b = " + b);
            System.out.println("c = " + c);
            System.out.println("d = " + d.get());
        }

        public synchronized void plus() {
            c++;
        }
    }

}

运行结果:

a = 9905
b = 9748
c = 10000
d = 10000

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值