Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如果我使用==_Java_Multithreading_Singleton - Fatal编程技术网

Java 如果我使用==

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

我不确定我的代码是否正确,我想确认不同的线程使用的不安全的singleton方法将获得difference对象,但结果总是打印为true

后面是我的代码,我不确定从线程获取实例的方式是否正确

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的方法,请参阅。