在安卓test包下进行网络请求时,会遇到子线程中网络请求结果无法输出打印的问题,于是想到利用java多线程并发包下相关类来实现线程同步,特此记录。
@RunWith(BlockJUnit4ClassRunner.class)
public class ThreadUnitTest {
private ReentrantLock lock;
private Semaphore semaphore;
/*
* countDownLatch数量不为0时,调用await会阻塞线程,countDown方法使数量减1
*/
private CountDownLatch countDownLatch;
/**
* 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。
* 公共屏障点--即初始化时给定的数值大小,
* cyclicBarrier 可以用 reset 方法重置等待的线程
*/
private CyclicBarrier cyclicBarrier;
/**
* 在每一个测试方法调用之前执行
*/
@Before
public void before(){
/**
* lock 和 synchronized主要都是对资源的保护,可以实现在一个时间点,
* 一个资源或操作,只被一条线程读写或执行。
* semaphore主要能实现限制线程执行的数量
* CountDownLatch和CyclicBarrier能实现一组线程等待或同时执行
*/
semaphore = new Semaphore(1);
lock = new ReentrantLock();
countDownLatch = new CountDownLatch(1); //主线程等待,子线程执行完成后释放数量
cyclicBarrier = new CyclicBarrier(2); //主线程和网络请求子线程两个线程
}
class SemaphoreRunnable implements Runnable{
int index;
public SemaphoreRunnable(int i){
index = i;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
try {
System.out.println(String.format("当前线程%s,剩余信号量:%d",
threadName,semaphore.availablePermits()));
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("当前线程%s,剩余信号量:%d",
threadName,semaphore.availablePermits()));
/**
* 如果注释该行,由于信号量总数为1,前面acquire后数量减1,剩余的数量为0,
* 导致所有线程都被阻塞,无法继续执行
*/
semaphore.release();
if(index == 24){
countDownLatch.countDown();
}
}
}
Runnable loginRunnable = new Runnable() {
@Override
public void run() {
String username = "xxxxxxxxx";
String password = "123456";
//构造用户登录json对象
final UserLoginPostBean postBean = new UserLoginPostBean();
postBean.setLoginName(username);
postBean.setPassword(password);
HttpRequestFactory.post(postBean,"suburl",
new ResultCallback<String>() {
@Override
public void onError(Call<String> request, Throwable e) {
synchronized (ThreadUnitTest.class) {
ThreadUnitTest.class.notify();
}
//该方法会让countDownLatch数量减1
countDownLatch.countDown();
try {
cyclicBarrier.await();
} catch (BrokenBarrierException e1) {
e1.printStackTrace();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
@Override
public void onResponse(String response) {
//唤醒其它等待的线程
synchronized (ThreadUnitTest.class) {
ThreadUnitTest.class.notify();
}
//该方法会让countDownLatch数量减1
countDownLatch.countDown();
try {
cyclicBarrier.await();
} catch (BrokenBarrierException e1) {
e1.printStackTrace();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
});
}
};
@Test
public void testWaitAndNotify() {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
threadPool.execute(loginRunnable);
try {
//让主线程进入阻塞,待网络请求子线程完成请求后会被唤醒
synchronized (ThreadUnitTest.class) {
ThreadUnitTest.class.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法结束,我最后执行");
}
@Test
public void testSemaphore(){
ExecutorService threadPool = Executors.newFixedThreadPool(10);
for(int i=0;i<25;i++) {
SemaphoreRunnable sr = new SemaphoreRunnable(i);
threadPool.execute(sr);
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法结束,我最后执行");
}
@Test
public void testCountDownLatch(){
ExecutorService threadPool = Executors.newSingleThreadExecutor();
threadPool.execute(loginRunnable);
try {
//countDownLatch 的 await方法会阻塞线程一直到 countDownLatch数量为0
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法结束,我最后执行");
}
@Test
public void testCountDownLatch2(){
// 开始的倒数锁
final CountDownLatch begin = new CountDownLatch(1);
// 结束的倒数锁
final CountDownLatch end = new CountDownLatch(10);
// 十名选手
final ExecutorService exec = Executors.newFixedThreadPool(10);
for (int index = 0; index < 10; index++) {
final int NO = index + 1;
Runnable run = new Runnable() {
public void run() {
try {
begin.await();// 一直阻塞
Thread.sleep((long) (Math.random() * 10000));
System.out.println("No." + NO + " arrived");
} catch (InterruptedException e) {
} finally {
end.countDown();
}
}
};
exec.submit(run);
}
System.out.println("Game Start");
begin.countDown();
try {
end.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Game Over");
exec.shutdown();
}
@Test
public void testCyclicBarrier(){
ExecutorService threadPool = Executors.newSingleThreadExecutor();
threadPool.execute(loginRunnable);
try {
/**
* cyclicBarrier 的 await方法会阻塞线程一直到调用 await方法的
* 线程数量达到初始化时给定的数量为止
*/
System.out.println(String.format("正在等待的线程数:%d",
cyclicBarrier.getParties()));
cyclicBarrier.await(); //这里调用加上上面执行runnable里的调用,刚好两次,线程结束阻塞
cyclicBarrier.reset(); //重置了后,又可以阻塞两条线程
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println("我要休眠五秒。。。。");
Thread.sleep(5000); //休眠两秒,
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Runnable() { //又开启一个子线程来调用await结束阻塞
@Override
public void run() {
try {
cyclicBarrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
try {
cyclicBarrier.await(); //调用该方法后,主线程被阻塞
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法结束,我最后执行");
}
private static int[] timeWalk = { 5, 8, 15, 15, 10 };
// 自驾游
private static int[] timeSelf = { 1, 3, 4, 4, 5 };
// 旅游大巴
private static int[] timeBus = { 2, 4, 6, 6, 7 };
/**
* CyclicBarrier最重要的属性就是参与者个数,另外最要方法是await()。
* 当所有线程都调用了await()后,就表示这些线程都可以继续执行,否则就会等待。
*/
@Test
public void testCyclicBarrier2(){
// 三个旅行团
CyclicBarrier barrier = new CyclicBarrier(4);
ExecutorService exec = Executors.newFixedThreadPool(3);
exec.submit(new Tour(barrier, "WalkTour", timeWalk));
exec.submit(new Tour(barrier, "SelfTour", timeSelf));
// 当我们把下面的这段代码注释后,会发现,程序阻塞了,无法继续运行下去。
exec.submit(new Tour(barrier, "BusTour", timeBus));
try {
barrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
exec.shutdown();
}
@Test
public void testReentrantLock() {
ExecutorService service = Executors.newCachedThreadPool();
TestReentrantLock lock = new TestReentrantLock();
for (int i = 0; i < 10; i++) {
service.submit(new MyReentrantLock(i, lock));
}
service.shutdown();
}
@Test
public void testFuture(){
final ExecutorService exe=Executors.newFixedThreadPool(3);
Callable<String> call=new Callable<String>(){
public String call() throws InterruptedException {
return "Thread is finished";
}
};
Future<String> task=exe.submit(call);
String obj= null;
try {
obj = task.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(obj+"进程结束");
System.out.println("总进程结束");
exe.shutdown();
}
}