mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
= fix BooleanMutex's inner Sync to static class and add test case
This commit is contained in:
@@ -32,7 +32,7 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
|||||||
*/
|
*/
|
||||||
public class BooleanMutex {
|
public class BooleanMutex {
|
||||||
|
|
||||||
private Sync sync;
|
private final Sync sync;
|
||||||
|
|
||||||
public BooleanMutex(){
|
public BooleanMutex(){
|
||||||
sync = new Sync();
|
sync = new Sync();
|
||||||
@@ -47,7 +47,7 @@ public class BooleanMutex {
|
|||||||
/**
|
/**
|
||||||
* 阻塞等待Boolean为true
|
* 阻塞等待Boolean为true
|
||||||
*
|
*
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException if the current thread is interrupted
|
||||||
*/
|
*/
|
||||||
public void get() throws InterruptedException {
|
public void get() throws InterruptedException {
|
||||||
sync.innerGet();
|
sync.innerGet();
|
||||||
@@ -86,7 +86,7 @@ public class BooleanMutex {
|
|||||||
* Synchronization control for BooleanMutex. Uses AQS sync state to
|
* Synchronization control for BooleanMutex. Uses AQS sync state to
|
||||||
* represent run status
|
* represent run status
|
||||||
*/
|
*/
|
||||||
private final class Sync extends AbstractQueuedSynchronizer {
|
private static final class Sync extends AbstractQueuedSynchronizer {
|
||||||
|
|
||||||
private static final long serialVersionUID = 2559471934544126329L;
|
private static final long serialVersionUID = 2559471934544126329L;
|
||||||
/** State value representing that TRUE */
|
/** State value representing that TRUE */
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package com.alibaba.otter.canal.common.utils;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class BooleanMutexTest {
|
||||||
|
|
||||||
|
public static final int CONCURRENCY = 10;
|
||||||
|
private ExecutorService executorService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
executorService = Executors.newFixedThreadPool(CONCURRENCY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
if (executorService != null) {
|
||||||
|
executorService.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 3000L)
|
||||||
|
public void testBooleanMutexGet() throws Exception {
|
||||||
|
|
||||||
|
BooleanMutex mutex = new BooleanMutex();
|
||||||
|
|
||||||
|
AtomicLong atomicLong = new AtomicLong(0);
|
||||||
|
|
||||||
|
Phaser phaser = new Phaser(CONCURRENCY + 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < CONCURRENCY; i++) {
|
||||||
|
executorService.submit(() -> {
|
||||||
|
try {
|
||||||
|
// arrive phase1 and wait until phase1 finish
|
||||||
|
int phase1 = phaser.arrive();
|
||||||
|
phaser.awaitAdvanceInterruptibly(phase1);
|
||||||
|
|
||||||
|
mutex.get();
|
||||||
|
atomicLong.addAndGet(1);
|
||||||
|
|
||||||
|
// arrive phase2
|
||||||
|
phaser.arrive();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(0, atomicLong.get());
|
||||||
|
|
||||||
|
// arrive phase1 and wait until phase1 finish
|
||||||
|
int phase1 = phaser.arrive();
|
||||||
|
phaser.awaitAdvanceInterruptibly(phase1);
|
||||||
|
assertEquals(0, atomicLong.get());
|
||||||
|
|
||||||
|
mutex.set(true);
|
||||||
|
|
||||||
|
// arrive phase2 and wait until phase2 finish
|
||||||
|
int phase2 = phaser.arrive();
|
||||||
|
phaser.awaitAdvanceInterruptibly(phase2);
|
||||||
|
assertEquals(CONCURRENCY, atomicLong.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test(timeout = 30000L, expected = TimeoutException.class)
|
||||||
|
public void testBooleanMutexBlock() throws Exception {
|
||||||
|
|
||||||
|
BooleanMutex mutex = new BooleanMutex();
|
||||||
|
|
||||||
|
AtomicLong atomicLong = new AtomicLong(0);
|
||||||
|
|
||||||
|
Phaser phaser = new Phaser(CONCURRENCY + 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < CONCURRENCY; i++) {
|
||||||
|
executorService.submit(() -> {
|
||||||
|
try {
|
||||||
|
// arrive phase1 and wait until phase1 finish
|
||||||
|
int phase1 = phaser.arrive();
|
||||||
|
phaser.awaitAdvanceInterruptibly(phase1);
|
||||||
|
|
||||||
|
mutex.get();
|
||||||
|
atomicLong.addAndGet(1);
|
||||||
|
|
||||||
|
// arrive phase2
|
||||||
|
phaser.arrive();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(0, atomicLong.get());
|
||||||
|
|
||||||
|
// arrive phase1 and wait until phase1 finish
|
||||||
|
int phase1 = phaser.arrive();
|
||||||
|
phaser.awaitAdvanceInterruptibly(phase1);
|
||||||
|
assertEquals(0, atomicLong.get());
|
||||||
|
|
||||||
|
// mutex is still false
|
||||||
|
mutex.set(false);
|
||||||
|
|
||||||
|
|
||||||
|
// arrive phase2 and wait until phase2 finish
|
||||||
|
int phase2 = phaser.arrive();
|
||||||
|
// will throw interrupted exception when timeout because mutex is still false
|
||||||
|
phaser.awaitAdvanceInterruptibly(phase2, 2, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
fail("unreachable code");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user