本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
上文(《Java并发编程:线程安全性》)给大家介绍了多线程的优缺点,以及线程安全的概念及实现方式,而本片文章将给大家介绍的是发布与逸出,错误的发布与逸出将会引发线程安全性问题。
发布
将线程的对象放在公共域,使其他线程可见,即为发布。
发布的方式主要有三种:
1. 将要发布的对象使用public修饰,这样其它类即可看见。代码如下:
public class Test {
public List<String> userNames = new ArrayList<>();
}
2. 通过公共方法将私有变量的引用返回,代码如下:
public class Test {
private List<String> userNames = new ArrayList<>();
public List<String> getUserNames(){
return userNames;
}
}
上述代码中,列表userNames虽然是私有变量,但是getUserNames方法将其引用发布出去后,其它类也可访问。
3. 匿名内部类方式。
public class Test {
public void start(){
Thread thread = new Thread(new Runable(){
@Override
public void run(){
System.out.println("do some things...");
}
});
thread.start();
}
}
上述代码中,使用new Runable创建了一个匿名内部类,在此过程中,Test类隐式地向Runable发布了一个this对象,在匿名内部类中可Test类对象。
逸出
错误的发布,即为逸出。
public class Test {
private Thread thread;
public Test(){
thread = new Thread(new Runable(){
@Override
public void run(){
System.out.println("do some things...");
}
});
}
}
上述代码中,在Test类的构造器中进行匿名内部类创建,在这过程中,Java要把Test类的当前对象传给Runable,但是由于这是在构造器中,对象还未创建成功,因此就会出现错误的发布。
安全的发布方式
- 将对象放在静态域中。对象会在初次使用Test类的时候进行初始化。
public class Test {
public static Object obj = new Object();
}
- 将对象放在final域中。
- 使用volatile修饰或者使用AtomicReference
- 使用锁
- 事实不可变对象。即对象没有用final修饰,但是在使用过程中,对象不会被修改。
后言
既然看到这里了,感觉有所收获的朋友,不妨来个大大的点赞吧~~~