Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.mprew.be.service.x;
- import static org.junit.Assert.assertEquals;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Timer;
- import java.util.TimerTask;
- import org.junit.Test;
- /**
- * This is an interesting test case that seems to be indicating a JRE issue.
- *
- * This comes from http://stackoverflow.com/q/10982941/179850 and the poster named "Luke".
- *
- * I've boiled the code down to its lowest level and added some comments around the changes that can change the error
- * count. This is pretty repeatable to me with 4/5 runs generating errors. If you can't get it to fail I'd try
- * decreasing the fixed-rate period and increasing the NUMBER_TO_USE constant.
- */
- public class StrangeRaceConditionTest {
- // if this is decreased it may remove the errors
- public static final int NUMBER_TO_USE = 1000000;
- private Map<Integer, Buffer> bufferMap = new HashMap<Integer, Buffer>();
- public static void main(String[] args) {
- new StrangeRaceConditionTest().strangeRaceConditionTest();
- }
- @Test
- public void strangeRaceConditionTest() {
- final Buffer buffer = getBuffer();
- TimerTask getBufferTask = new TimerTask() {
- @Override
- public void run() {
- buffer.getBuffer();
- }
- };
- // if the period is increased it seems to reduce the errors
- new Timer(true).scheduleAtFixedRate(getBufferTask, 0 /* delay ms */, 10 /* period ms */);
- for (long i = 0; i < NUMBER_TO_USE; i++) {
- // if we inline the remove() method here then no errors
- // if we change this to buffer.remove() then no errors
- remove();
- }
- assertEquals(0, buffer.getErrorC());
- }
- private synchronized void remove() {
- Buffer buffer = getBuffer();
- buffer.remove();
- }
- private synchronized Buffer getBuffer() {
- // if we remove this whole map nonesense then no errors
- Buffer buffer = bufferMap.get(1);
- // if this test/else is flipped so it is buffer == null ... then no errors
- if (buffer != null) {
- // if this line is commented out then no errors
- buffer = bufferMap.get(1);
- } else {
- buffer = new Buffer();
- bufferMap.put(1, buffer);
- }
- return buffer;
- }
- // moving this out to its own class file doesn't seem to help
- private static class Buffer {
- private List<Integer> list = new ArrayList<Integer>();
- private boolean insideGetBuffer = false;
- private int errorC = 0;
- public Buffer() {
- // initialize the list
- for (long i = 0; i < NUMBER_TO_USE; i++) {
- list.add(null);
- }
- }
- public synchronized void remove() {
- if (insideGetBuffer) {
- // adding a System.out.println here makes the problem more repeatable
- // System.out.println("How did we get here?");
- errorC++;
- }
- }
- public synchronized void getBuffer() {
- insideGetBuffer = true;
- try {
- // if you comment out this sleep then no errors
- Thread.sleep(5);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- insideGetBuffer = false;
- }
- }
- public synchronized int getErrorC() {
- return errorC;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement