java关键字:volatile、synchronized

1、volatile关键字

变量值的同步:

volatile可以强制从公共内存中读取变量的值,再同步到私有内存中。多个线程可以操作同一个对象内的变量,一个线程做出更改后,可以被其他线程感知。


public class SelfMain {
    private static volatile boolean flag = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            for(int i = 0; i < 1000; i++) {
                if(flag) {
                    System.out.println("flag is true----" + i);
                }else {
                    System.out.println("flag is false----" + i);
                
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();

        new Thread(() -> {
            flag = true;
        }).start();

    }
}

输出:

flag is false----0
flag is true----1
flag is true----2
flag is true----3
flag is true----4
flag is true----5
flag is true----6
flag is true----7
flag is true----8
禁止代码重排序:

java程序在运行时,jit(即使编译器)会对代码进行优化,此时可能会对代码进行重排序,调整代码中方法执行的顺序(将耗时轻的代码先执行)。

volatile之前的代码不能放到volatile之后,同样volatile之后的代码不能放到volatile之前。但是volatile之前或者之后的代码可以进行重新排序,但是不能越过volatile。

同样synchronized同样具有禁止代码重排序的功能,与volatile禁止代码重排序的规则一样。

2、synchronized 关键字

synchronized是给当前对象加锁,synchronized包围的代码称为临界区
2.1 synchronized加在代码块或普通方法上

对于所有带有synchronized关键字的非静态方法和synchronized(this)的代码块,它们都是同一把锁,只允许一个线程执行。

class DoSomeThingA {
    synchronized public void printSomeThingA() throws InterruptedException {
        System.out.println("正在执行---" + Thread.currentThread().getName());
        System.out.println("正在退出---" + Thread.currentThread().getName());
    }
}
2.2 synchronized关键字如果加在静态方法上

同一个class的所有对象,所有的静态类方法都是一把锁,同时只允许一个线程调用。

2.3 对于对象加锁

如果不是同一个对象,那么就不是同一把锁。例如同一个对象内的 synchronized(“AA”)、 synchronized(“BB”)、可以由多个线程并行执行,它们是对不同字符串对象进行了加锁。

对合理的代码块进行加锁,不仅能够保证多线程操作的安全性,还能够提高程序执行的效率。

synchronized 一般不对String对象进行加锁,因为字符串常量一般都是存放在常量池的,给字符串常量加锁可能会导致其它的一些问题,可以实例化一个对象 new Object() 给对象加锁。或者new String() 创建一个不同的字符串对象。

class DoSomeThingA {
    public void printSomeThingA() throws InterruptedException {
        synchronized("AA"){
            System.out.println("正在执行printSomeThingA---" + Thread.currentThread().getName());
            System.out.println("正在退出printSomeThingA---" + Thread.currentThread().getName());
        }
    }

    public void printSomeThingB() throws InterruptedException {
        synchronized("BB"){
            System.out.println("正在执行printSomeThingB---" + Thread.currentThread().getName());
            System.out.println("正在退出printSomeThingB---" + Thread.currentThread().getName());
        }
    }

}

2.4 synchronized会使线程私有内存变量与公有内存变量同步

public class SelfMain {


    public static void main(String[] args) throws InterruptedException {


        DoSomeThingB doSomeThing = new DoSomeThingB();

        new Thread(() -> {
            try {
                doSomeThing.printSomeThingA();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();

        Thread.sleep(3000);

        new Thread(() -> {
            try {
                doSomeThing.printSomeThingB();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();

    }

}


class DoSomeThingB {
    private boolean running = true;

    public void printSomeThingA() throws InterruptedException {
        System.out.println("正在执行---" + Thread.currentThread().getName());
        while (running){
            synchronized ("AA"){
            }
        }
        System.out.println("正在退出---" + Thread.currentThread().getName());
    }

    public void printSomeThingB() throws InterruptedException {
        System.out.println("修改---" + Thread.currentThread().getName());
        running = false;
    }
}

如果不加synchronized (“AA”){ },即使另外一个线程调用printSomeThingB方法,修改running也不会使第一个线程停止。
同样如果将synchronized (“AA”){ },替换成Thread.sleep(1000)也会使,私有变量在内存中具有可见性。

3、锁重入

当一个线程在执行一个对象加了synchronized关键字的方法时,它就获得了这个对象的锁,此时它可以同时执行该对象其它加了synchronized关键字的方法和代码块。同时它也可以调用父类加了synchronized关键字的方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值