创建一个JUnit,如果在singelton的Java Spring实现中GetInstance()未同步,该JUnit将失败
在一次job intreview期间,我被分配了一项任务来实现一个toy Singelton数据库和一个用户控制器,通过使用Spring依赖项注入来使用该数据库。 我提出了这个版本: 辛格尔顿分贝创建一个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
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;
}
}