public class Response_Unit_Manager {
private static HashMap<String, Response_Unit> Response_Unit_DB =
new HashMap<> ();
/**
*
* This subprogram adds a new Response_Unit to the data store. The
* new response unit must be valid Response_Unit object and it's ID must be
* unique (i.e., must not already exist in the data store.
*
* Exceptions Thrown: Null_Object_Exception
*/
public static void Add_Response_Unit (Response_Unit New_Unit)
throws Null_Object_Exception, Duplicate_Item_Exception {
String Unit_ID = New_Unit.Unit_ID ();
if (New_Unit == null)
throw new Null_Object_Exception ();
else if (Response_Unit_Exists (Unit_ID))
throw new Duplicate_Item_Exception (Unit_ID);
else
Response_Unit_DB.put (Unit_ID, New_Unit);
} //end Add_Response_Unit
答案 0 :(得分:0)
运行测试时可能会很幸运,但是失败的代码并不意味着它是线程安全的代码。检查线程安全性的唯一自动方法是使用一些静态分析工具,您可以在方法/类上添加注释并扫描潜在问题。例如,我知道FindBugs支持一些注释并基于它们进行并发检查。您应该能够将此应用于您的单个Tester类。在这个主题上,业界仍有很大的改进空间,但现在有一些例子:
答案 1 :(得分:0)
正如其他人所说,你不能写一个能保证失败的测试,因为线程安排可能“只是工作”,但你可以编写非常传递概率低的测试如果有线程安全问题。例如,您的代码尝试禁止数据库中的重复项,但由于线程安全问题,它无法执行此操作。因此产生了大量的线程,让它们都等待CountdownLatch
或其他什么来最大化你触发比赛的机会,然后让他们都尝试插入相同的项目。最后,您可以检查(a)除了一个线程之外的所有线程都看到Duplicate_Item_Exception
和(b)Response_Unit_DB只包含一个项目。对于这些类型的测试,您也可以多次运行(在同一测试中),以最大限度地提高触发问题的机会。
以下是一个例子:
@Test
public void testIsThreadSafe() {
final int NUM_ITERATIONS = 100;
for(int i = 0; i < NUM_ITERATIONS; ++i) {
oneIsThreaSafeTest();
}
}
public void oneIsThreadSafeTest() {
final int NUM_THREADS = 1000;
final int UNIT_ID = 1;
final Response_Unit_Manager manager = new Response_Unit_Manager();
ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS);
CountdownLatch allThreadsWaitOnThis = new CountdownLatch(1);
AtomicInteger numThreadsSawException = new AtomicInteger(0);
for (int i = 0; i < NUM_THREADS; ++i) {
// this is a Java 8 Lambda, if using Java 7 or less you'd use a
// class that implements Runnable
exec.submit(() -> {
allThreadsWaitOnThis.await();
// making some assumptions here about how you construct
// a Response_Unit
Response_Unit unit = new Response_Unit(UNIT_ID);
try {
manager.Add_Response_Unit(unit);
} catch (Duplicate_Item_Exception e) {
numThreadsSawException.incrementAndGet();
}
});
// release all the threads
allThreadsWaitOnThis.countdown();
// wait for them all to finish
exec.shutdown();
exec.awaitTermination(10, TimeUnits.MINUTES);
assertThat(numThreadsSawException.get()).isEqualTo(NUM_THREADS - 1);
}
您可以为其他潜在的线程安全问题构建类似的测试。
答案 2 :(得分:0)
查找测试错误的最简单方法(如类中包含的错误)是使用Testrunner,例如以下内容:
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
@Provider
public class NoContentToOkResposeFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
if (responseContext.getStatus() == 204) {
responseContext.setStatus(200);
}
}
}
使用动态竞赛条件检测工具,如http://vmlens.com,一种轻量级竞赛状态检测器。这将显示以下竞争条件:
堆栈跟踪导致错误。在左侧写入,右侧为读取。
http://vmlens.com适用于eclipse,所以它依赖于你正在使用的ide,如果它对你有用