final 修改的变量一定是不可修改的么?

155 阅读1分钟

前言

看到final,我们知道final是修饰变量、类和方法的,其变量不可修改、类不能被继承、方法不能被覆盖。这是final我们知道的知识点,但是它就一定能保证原子性么?答案是否定的。

Final修饰的引用代码

package com.example.auth.config;


public class FinalExample {

    //引用变量
    final int[] ints ;

  static FinalExample object;

    public FinalExample() {
        ints =new int[1];
        ints[0]=1;
    }

    public static void writer(){
        object = new FinalExample();
        int temp1 =object.ints[0];
        System.out.println("ints数组第一次写的值为:"+temp1);
    }
    public static void writerTwo(){
        object.ints[0]=2;
        int temp2 =object.ints[0];
        System.out.println("ints数组第二次写的值为:"+temp2);
    }
    public static void reader(){
        if (object!=null){
            int temp3 =object.ints[0];
            System.out.println("ints数组第一个值为:"+temp3);
        }
    }

    public static void main(String[] args) {
        Writer writer = new Writer();
        WriterTwo writerTwo =new WriterTwo();
        Reader reader =new Reader();
        new Thread(writer,"线程A").start();
        new Thread(writerTwo,"线程B").start();
        new Thread(reader,"线程C").start();

    }

     static class Writer implements Runnable{
        @Override
        public void run() {

            try {
                System.out.println(Thread.currentThread().getName()+"执行第一次写的操作");
                writer();

                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

     static class WriterTwo implements Runnable{
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName()+"执行第二次写的操作");
                writerTwo();

                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

     static class Reader implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"执行读数据操作");
            reader();

            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

这里创建3个线程A、B、C,线程A、B分别对ints引用变量进行2次赋值,线程C对复制的变量进行读。

让我们看看运行的结果,可以看出经过final修饰的引用变量的值被修改了。

8859B7A8-3923-48E4-B37D-88AA8F4028CC.png

总结

Final修饰的变量可以在声明的时候或者在构造的时候赋值,且只能在这两个地方赋值,赋值后再不能进行改变,但是对于final修饰的引用,只是引用不能再指向其他对象,但其所指对象的属性还是可以被修改的,final只有可见性。