创建一个JUnit,如果在singelton的Java Spring实现中GetInstance()未同步,该JUnit将失败

创建一个JUnit,如果在singelton的Java Spring实现中GetInstance()未同步,该JUnit将失败,java,spring,design-patterns,asynchronous,junit,Java,Spring,Design Patterns,Asynchronous,Junit,在一次job intreview期间,我被分配了一项任务来实现一个toy Singelton数据库和一个用户控制器,通过使用Spring依赖项注入来使用该数据库。 我提出了这个版本: 辛格尔顿分贝 package SingeltonDBVersion2; import GlobalSetting.User; public class SingeltonDB { private static DBconnImpl db = null; private static Singel

在一次job intreview期间,我被分配了一项任务来实现一个toy Singelton数据库和一个用户控制器,通过使用Spring依赖项注入来使用该数据库。 我提出了这个版本:

辛格尔顿分贝

package SingeltonDBVersion2;

import GlobalSetting.User;

public class SingeltonDB {
    private static DBconnImpl db = null;
    private static SingeltonDB singalDb = null;

    private SingeltonDB(String username, String password) {
        db = new DBconnImpl();
    }

    public synchronized static SingeltonDB getInstance(String username,
            String password) throws Exception {

        if (db != null) {
            return singalDb;
        }
        System.out.println("The database is now open");
        singalDb = new SingeltonDB(username, password);
        db.connect(username, password);
        System.out.println("The database was connected");
        singalDb.create("table1");
        return singalDb;
    }

    public void create(String tableName) throws Exception {
        db.create(tableName);
    }

    public User query(String tableName, int rowID) throws Exception {
        if (db == null) {
            System.out.println("Error: the database is not open");
            return null;
        }
        return (db.query(tableName, rowID));
    }

    public void update(String tableName, User user) throws Exception {
        if (db == null) {
            System.out.println("Error: the database is not open");
            return;
        }
        db.update(tableName, user);
    }

}
用户控制器

package SingeltonDBVersion2;

import GlobalSetting.IUserContorller;
import GlobalSetting.User;

/****************************************************************************
 * This is class is an implementation of a UserContorller for the version with
 * Spring, because here we use inversion of control. The UserContorller
 * constructor takes the an object of SingeltonDB which we are passing using
 * Spring Dependency Injection in our UnitTests
 *****************************************************************************/
public class UserContorller implements IUserContorller {
    SingeltonDB db;

    public UserContorller(SingeltonDB db) throws Exception {
        this.db = db;
    }

    @Override
    public void createTable(String table) throws Exception {
        db.create(table);

    }

    @Override
    public void saveUser(String table, int id, String name, int age)
            throws Exception {

        db.update(table, new User(id, name, age));
    }

    @Override
    public User getUser(String table, int id) throws Exception {

        return db.query(table, id);
    }

}
spring.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="MyUserContorller" class="SingeltonDBVersion2.UserContorller">
        <constructor-arg ref="MySingeltonDB" />
    </bean>
    <bean id="MySingeltonDB" class="SingeltonDBVersion2.SingeltonDB"
        factory-method="getInstance">
        <constructor-arg value="MyAccount" />
        <constructor-arg value="123" />
    </bean>

</beans>
现在,我被要求编写一个测试(比如Junit),如果SingleTondb的getinstance()方法不同步,该测试将失败。。。 我真的不知道怎么做

有人能帮忙提供一个解决方案吗?
谢谢

默认情况下,当您创建上下文时,所有单例bean都会被实例化。因此,在您的情况下,请避免:

<bean id="MyUserContorller" class="SingeltonDBVersion2.UserContorller" lazy-init="true">
 ....
<bean id="MySingeltonDB" class="SingeltonDBVersion2.SingeltonDB" factory-method="getInstance" lazy-init="true">

现在创建多个线程实例,并将它们一起启动,并在hashcode表单上断言每个线程的不相等性。如果你得到相等的分数,你的测试就会失败,你想要的是什么。

almas shaikh,这是我写的代码:

package Tests;

import java.util.concurrent.CountDownLatch;


import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;



public class SingeltonDBVersion2TestSynch {

    static ApplicationContext Context;

    @Test
    public void testSynch() throws Exception {

        int num = 100;

        Context = new ClassPathXmlApplicationContext("spring.xml");

        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(num);
        MyThread[] threads = new MyThread[num];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new MyThread(Context, startSignal, doneSignal);
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
        startSignal.countDown();
        doneSignal.await();
        for (int i = 0; i < threads.length; i++) {
            System.out.println(threads[i].getHashCode());
        }
    }
}

class MyThread extends Thread {
    private ApplicationContext context;
    private int hashCode;
    CountDownLatch startSignal;
    CountDownLatch doneSignal;

    public MyThread(ApplicationContext context, CountDownLatch startSignal,
            CountDownLatch doneSignal) {
        this.context = context;
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }

    public void run() {
        try {
            startSignal.await();
            hashCode = System
                    .identityHashCode(context.getBean("MySingeltonDB"));
            doneSignal.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public int getHashCode() {
        return hashCode;
    }
}
包测试;
导入java.util.concurrent.CountDownLatch;
导入org.junit.Test;
导入org.springframework.context.ApplicationContext;
导入org.springframework.context.support.ClassPathXmlApplicationContext;
公共类SingleTondbVersion2TestSynch{
静态应用上下文上下文;
@试验
public void testSynch()引发异常{
int num=100;
Context=newclasspathXmlApplicationContext(“spring.xml”);
CountDownLatch startSignal=新的CountDownLatch(1);
CountDownLatch doneSignal=新的CountDownLatch(num);
MyThread[]线程=新的MyThread[num];
对于(int i=0;i
我只是想打印哈希代码以进行检查。。。但它们都有相同的哈希代码(我更改了SpringXML,并从getInstacnec()中删除了eynchronized)。
myabe我在倒计时时没有用正确的方法?

谢谢这是一个很好的处理方法,但是我有一个问题。。。首先,您通过在getInstance方法中打印来引入一些同步,因为多个线程必须在输出流上同步。其次,仅仅运行大量线程并希望出现某种情况可能是行不通的。如果您想在测试中显示它,您可能需要在测试null之后添加一个sleep in getInstance(),这样就有可能多个线程到达同一点。
class MyThread extends Thread {
     private ApplicationContext context;
     private int hashCode;
     public MyThread(ApplicationContext context) {
         this.context = context;
     }
     public void run() {
         hashCode = System.identityHashCode(context.getBean("MySingeltonDB"));
     }
     public int getHashCode() { 
         return hashCode;
     }
}
package Tests;

import java.util.concurrent.CountDownLatch;


import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;



public class SingeltonDBVersion2TestSynch {

    static ApplicationContext Context;

    @Test
    public void testSynch() throws Exception {

        int num = 100;

        Context = new ClassPathXmlApplicationContext("spring.xml");

        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(num);
        MyThread[] threads = new MyThread[num];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new MyThread(Context, startSignal, doneSignal);
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
        startSignal.countDown();
        doneSignal.await();
        for (int i = 0; i < threads.length; i++) {
            System.out.println(threads[i].getHashCode());
        }
    }
}

class MyThread extends Thread {
    private ApplicationContext context;
    private int hashCode;
    CountDownLatch startSignal;
    CountDownLatch doneSignal;

    public MyThread(ApplicationContext context, CountDownLatch startSignal,
            CountDownLatch doneSignal) {
        this.context = context;
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }

    public void run() {
        try {
            startSignal.await();
            hashCode = System
                    .identityHashCode(context.getBean("MySingeltonDB"));
            doneSignal.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public int getHashCode() {
        return hashCode;
    }
}