如果getInstance()在单例的Java Spring实现中未同步,则创建一个失败的JUnit

时间:2014-12-19 10:55:25

标签: java spring design-patterns asynchronous junit

我在作业期间给了一个任务来实现一个玩具Singelton数据库和一个使用Spring依赖注入来利用该数据库的用户控制器。 我推出了这个版本:

Singelton DB

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);
    }

}

UserContorller

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>

我可以这样使用它:

        ApplicationContext contex = new ClassPathXmlApplicationContext("spring.xml");
        UserContorller user1 = (UserContorller) contex.getBean("MyUserContorller");
        saveUser("table1", 1, Mike, 44); //add user with id 1 and age of 44

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

有人可以帮助提供灵魂吗? 谢谢!

2 个答案:

答案 0 :(得分:0)

默认情况下,所有单例bean都会在创建上下文时实例化。所以在你的情况下避免使用:

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

现在创建多个线程,如下所示:

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;
     }
}

现在创建多个线程实例并将它们全部启动,并在hashcode上断言,形成每个线程的非相等性。如果你得到平等,你的考试就会失败,你想要的是什么。

答案 1 :(得分:-1)

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;
    }
}

我只是尝试打印哈希码以进行检查......但它们都具有相同的哈希码(我更改了spring xml并从getInstacnec()中删除了eynchronized)。 myabe我在CountDownLacths中没有使用正确的方法吗?