线程的学习(三)

多线程的三大特性:原子性、可见性、有序性

1、原子性

即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

原子性其实就是保证数据一致、线程安全一部分,

一个很经典的例子就是银行账户转账问题:
比如从账户A向账户B转1000元,那么必然包括2个操作:
从账户A减去1000元,往账户B加上1000元。
这2个操作必须要具备原子性才能保证不出现一些意外的问题。

我们操作数据也是如此,
比如i = i+1;其中就包括,读取i的值,计算i,写入i。
这行代码在Java中是不具备原子性的,则多线程运行肯定会出问题,
所以也需要我们使用同步和lock这些东西来确保这个特性了。

2、可见性

当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能立即看得到修改的值。

若两个线程在不同的cpu,那么线程1改变了i的值还没刷新到主存,线程2又使用了i,那么这个i值肯定还是之前的,线程1对变量的修改线程没看到这就是可见性问题。

如何实现可见性呢:使用 volatile 关键字

举个简单例子:

public class VolatileDemo extends Thread{
    public volatile boolean flag = true;

    @Override
    public void run() {
        System.out.println("线程开始·········");
        while (flag){
        }
        System.out.println("线程结束·········");
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileDemo demo = new VolatileDemo();
        demo.start();
        sleep(3000);
        demo.flag = false;
        System.out.println("flag改成false");
        sleep(3000);
        System.out.println("flag:"+demo.flag);
    }
}

对于共享变量flag —— 是否有加volatile关键字 —— 输出的结果  有兴趣可以测试下

原理:可见性也就是说一旦某个线程修改了被volatitle 修饰的变量,它会保证修改的值会立即被跟新到住内存中,当有其他的线程需要读取的时候,可以立即获取到修改之后的值。

扩展:在java中为了加快程序运行的效率,对一些变量的操作通常是在该线程的寄存器或是CPU缓存上,之后才会同步到主内存中,而加了volatile修饰符的变量则可以直接读写主内存。

温馨提示:只要是全局共享变量 可以都加上volatile

synchronized和volatile的区别

1.volatile本质是下、在高速jvm当前变量咋寄存器当中的值是不确定的,需要从主存中读取,synchronizated则是锁住当前变量,只有当前线程可以访问该变量时,其他线程被阻塞
2.volatile只能使用在变量级别,而synchronizated可以使用在变量,方法和类级别
3.volatile可以改变线程的可见性,而Synchronized可以保证线程的可见性和原子性
4.volatile不会造成线程阻塞,而Synchronized会造成线程阻塞
5.volatile标记的变量不会被编译器优化,而Synchronized会被编译器优化
6.当一个域的值依赖他之前的值得时候volatile就无法工作,例如i++
7.volatile 的性能优于 synchronizated

3、有序性

程序执行的顺序按照代码的先后顺序执行。

一般来说处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。如下:

int a = 10; //语句1

int r = 2; //语句2

a = a + 3; //语句3

r = a*a; //语句4

则因为重排序,他还可能执行顺序为 2-1-3-4,1-3-2-4

但绝不可能 2-1-4-3,因为这打破了依赖关系。

显然重排序对单线程运行是不会有任何问题,而多线程就不一定了,所以我们在多线程编程时就得考虑这个问题了。

4、扩展

主内存  与 共享变量有关 —— 在线程中 共享变量 就放在其中;

JMM(Java Memory Model):java内存模型 —— 本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量,(包括实例字段,静态字段,和构成数组对象的元素)的访问方式.

 

synchronized实现可见性

 

 

posted @ 2020-03-29 01:37  An-Optimistic-Person  阅读(82)  评论(0编辑  收藏  举报