1.ThreadLocal
ThreadLocal .每个线程会在自己的线程缓存该属性的值,不会因为别的线程改变自己的线程发生改变,即使是同一个变量
public class Main {
public static void main(String[] args) {
//主线程
final ThreadLocal<Boolean> param = new ThreadLocal<>();
param.set(true);
System.out.println("主线程 ---"+param.get());
//1线程
new Thread("1"){
@Override
public void run() {
System.out.println("1线程---"+param.get());
}
}.start();
//2线程
new Thread("2"){
@Override
public void run() {
param.set(false);
System.out.println("2线程---"+param.get());
}
}.start();
}
}
三个线程都操作同一个变量,主线程,将param变成true,线程1直接读取,线程2false,最终的结果是:
2.内部类和final
匿名内部类格式出现的条件: 1.成员方法中的局部变量或者形参 2.匿名内部类,当匿名内部类直接调用局部变量时
例子1:只是简单的引用
1.png1.
a报错,因为a在内部类中引用.必须将a声明为final.
例子2:修改局部变量的值
2.png2.
a报错,因为在内部类中改变了a的值,这个时候需要将a变成数组
总结:在成员方法中使用其他外部类或者内部类时直接调用局部变量会有问题
1.只是使用,如例子1所示,需要添加final关键字因为没有修改所以只加final
2.修改局部变量的值,需要变成数组并添加final关键字修改了为了维护a的不变性只能让其是同一个对象所以变成数组
3.原因
内部类最终也会编译成class文件,其编译后的结果为
public class OuterClass$InnerClass {
public InnerClass(int a){
this.InnerClass$a = a;
}
...
}
内部类并不是直接调用局部参数,而是利用自身的构造器对传入的参数进行备份,自己内部方法调用的实际上时自己的属性而不是外部方法传递进来的参数。
在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的一致性,就规定使用final来避免形参的不改变。
4.实际中最常见的
开启一线程调用方法内部的局部变量或者形参
1:
final int a =0;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(a);
}
}).start();
2:
final int[] a =new int[]{0};
new Thread(new Runnable() {
@Override
public void run() {
a[0] = 10;
System.out.println(a);
}
}).start();
网友评论