Java 如果我使用==
我不确定我的代码是否正确,我想确认不同的线程使用的不安全的singleton方法将获得difference对象,但结果总是打印为true 后面是我的代码,我不确定从线程获取实例的方式是否正确Java 如果我使用==,java,multithreading,singleton,Java,Multithreading,Singleton,我不确定我的代码是否正确,我想确认不同的线程使用的不安全的singleton方法将获得difference对象,但结果总是打印为true 后面是我的代码,我不确定从线程获取实例的方式是否正确 class Singleton { private static Singleton singleton=null; private Singleton(){ System.out.println(Thread.currentThread().getName()+" Sing
class Singleton {
private static Singleton singleton=null;
private Singleton(){
System.out.println(Thread.currentThread().getName()+" Singleton init...");
}
public static Singleton getInstance(){
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
}
public class SingletonDemo{
public static void main(String[] args) throws ExecutionException, InterruptedException {
ArrayList<Singleton> arrayList = new ArrayList<>();
Callable<Singleton> obj = ()->{return Singleton.getInstance();};
ExecutorService executors = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
Future<Singleton> submit = executors.submit(obj);
arrayList.add(submit.get());
}
Singleton s1 = arrayList.get(0);
for (int i = 1; i < arrayList.size(); i++) {
System.out.println(s1==arrayList.get(i));
}
}
类单例{
私有静态单例单例=null;
私人单身人士(){
System.out.println(Thread.currentThread().getName()+“Singleton init…”);
}
公共静态单例getInstance(){
if(singleton==null){
singleton=新singleton();
}
返回单身;
}
}
公共类单音演示{
公共静态void main(字符串[]args)引发ExecutionException、InterruptedException{
ArrayList ArrayList=新的ArrayList();
可调用obj=()->{return Singleton.getInstance();};
ExecutorService executors=executors.newSingleThreadExecutor();
对于(int i=0;i<10;i++){
未来提交=执行人提交(obj);
add(submit.get());
}
Singleton s1=arrayList.get(0);
对于(int i=1;i
我知道您想证明您的代码不是线程安全的,它可能会中断。
没错,代码不是线程安全的
如果有两个线程A和B同时访问getInstance
方法,那么这两个线程都可能会看到它的null,并且都可能会获得该类的不同实例
但是,您编写的测试并不是完美的,为了破坏线程安全,我们需要一个争用条件,当两个或多个线程试图同时访问共享数据或资源时,就会出现争用条件
在您的SingletonDemo
中,您使用了Executors
,但您一次迭代并生成一个线程。由于线程是按顺序生成的,因此两个或多个线程在同时获取实例时发生冲突的可能性非常小
我们需要的是两个线程在完全相同的时间发生碰撞,如果它们在完全相同的时间启动,这是可能的(至少这是我们可以创建以增加碰撞概率的最小条件)
为此,我们需要一种称为CyclicBarrier的东西,我从一个SO答案中引用
现在让我们重写演示:
public class SingletonDemo {
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
final CyclicBarrier gate = new CyclicBarrier(3);
Thread t1 = new Thread() {
public void run() {
try {
gate.await();
Singleton.getInstance();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
};
Thread t2 = new Thread() {
public void run() {
try {
gate.await();
Singleton.getInstance();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
};
t1.start();
t2.start();
gate.await();
}
}
在这里,我们试图使用循环屏障同时跨越2个线程
现在,让我们修改Singleton
类以获得更好的日志记录:
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
}
public static Singleton getInstance() throws InterruptedException {
System.out.println("Requesting Thread" + Thread.currentThread()
.getName());
if (singleton == null) {
System.out.println("Created New Instance for " + Thread.currentThread()
.getName());
singleton = new Singleton();
}
return singleton;
}
}
现在,请尝试多次运行SingletonDemo,如果幸运的话,您可能会体验到您的类不是线程安全的,并获得如下日志:
Requesting ThreadThread-2
Requesting ThreadThread-1
Created New Instance for Thread-1
Created New Instance for Thread-2
这说明为两个线程都创建了实例,因此证明了线程安全性被破坏。您的推理是有缺陷的。线程不安全意味着:它有可能破坏。这并不意味着:它一定会失败。有时很难证明某个东西会破坏,但代码不是线程安全的,这是正确的e、 线程A和线程B没有理由不能同时执行
if
,并且都分配给singleton并返回,导致返回两个不同的实例(每个线程中一个)。这是因为多种原因(基本线程调度和单独的线程本地值缓存)。有关实现singleton的方法,请参阅。