Java多线程编程-CountDownLatch

前言:

本文是基于《Java多线程编程实战指南-核心篇》第五章个人理解,源码是摘抄作者的源码,源码会加上自己的理解。读书笔记目前笔者正在更新如下, 《Java多线程编程实战指南-核心篇》,《How Tomcat Works》,再到《spring 源码》解读。

CountDownLatch:

CountDownLatch可以用来实现一个(或者多个)线程等待其他线程完成一组特定的操作之后才继续运行。这组操作被称为先决操作。countDownLatch内部会维护一个用户未完成的先决操作熟练的计数器,当CountDownLatch.countDown()每被执行一次就会相应实例的计数器值减少1.而CountDownLatch.await()相当于一个受保护方法,其保护条件为“计数器值为0”,因此计数器值不为0时,执行线程会被暂停,而countDown()相当于一个通知方法,在计数器值达到0时唤醒相应实例上的所有等待线程。

其中有一点,当计数器的值为0之后,该计数器的值就不再发生变化,此时再次调用countDown()并不会导致异常的抛出,并且await的线程也不会暂停,因此countDownLatch的使用是一次性的,一个countDownLatch实例只能够实现一次等待和唤醒。

实战案例:

书本里介绍了一个web服务器实战案例,其启动时需要启动若干启动过程比较耗时的服务,为了尽可能减少服务器启动过程耗时,该服务器会使用专门的工作线程以并发的方式去启动服务,但是服务器在所有启动操作结束后,需要判断这些服务的状态以检查服务器的启动是否成功,只有所有服务启动成功情况下该服务器才被认为是启动成功的。

个人觉得这个web服务器器例子很好。

代码基本讲解:

1.ServiceStarter的main是主要流程,启动所有服务->检测所有服务->最后判断输出是否启动成功。

2.启动所有服务:封装在serviceManager的startServices中,实例化了一个CountDownLatch,并且实例化了A,BC三个服务。

3.A,B,C三个服务分别继承了AbstractService,而AbstractService同时实现了接口service。

其中AbstractService为子类预留了doStart函数由子类自行实现其业务内容,所以A,B,C继承AbstractService重写doStart。 同时子类A,B,C能调用父类AnstractService的start,stop,isStart进行线程启动/停止/检查。

4.检测所有服务:封装在serviceManager的checkServiceStatus的中,进行CountDownLatch.await(),等待所有线程都启动完毕,让标志位allIsOK=true

5.最后根据标志为allIsOK输出对应的日志。

代码:

public class CaseRunner5_2 {

  public static void main(String[] args) {
    ServerStarter.main(args);
  }

}
public class ServerStarter {

  public static void main(String[] args) {
    // 省略其他代码

    // 启动所有服务
    ServiceManager.startServices();

    // 执行其他操作

    // 在所有其他操作执行结束后,检测服务启动状态
    boolean allIsOK;
    // 检测全部服务的启动状态
    allIsOK = ServiceManager.checkServiceStatus();

    if (allIsOK) {
      System.out.println("All services were sucessfully started!");
      // 省略其他代码
    } else {
      // 个别服务启动失败,退出JVM
      System.err.println("Some service(s) failed to start,exiting JVM...");
      System.exit(1);
    }
    // ...
  }
}
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;

public class ServiceManager {
  static volatile CountDownLatch latch;
  static Set<Service> services;

  public static void startServices() {
    services = getServices();
    for (Service service : services) {
      service.start();
    }
  }

  public static boolean checkServiceStatus() {
    boolean allIsOK = true;
    // 等待服务启动结束
    try {
      latch.await();
    } catch (InterruptedException e) {
      return false;
    }

    for (Service service : services) {
      if (!service.isStarted()) {
        allIsOK = false;
        break;
      }
    }
    return allIsOK;
  }

  static Set<Service> getServices() {
    // 模拟实际代码
    latch = new CountDownLatch(3);
    HashSet<Service> servcies = new HashSet<Service>();
    servcies.add(new SampleServiceC(latch));
    servcies.add(new SampleServiceA(latch));
    servcies.add(new SampleServiceB(latch));
    return servcies;
  }
}
public interface Service {
	void start();
	void stop();
	boolean isStarted();
}
import java.util.concurrent.CountDownLatch;

public abstract class AbstractService implements Service {
  protected boolean started = false;
  protected final CountDownLatch latch;

  public AbstractService(CountDownLatch latch) {
    this.latch = latch;
  }

  @Override
  public boolean isStarted() {
    return started;
  }

  // 留给子类实现的抽象方法,用于实现服务器的启动逻辑
  protected abstract void doStart() throws Exception;

  @Override
  public void start() {
    new ServiceStarter().start();
  }

  @Override
  public void stop() {
    // 默认什么也不做
  }

  class ServiceStarter extends Thread {
    @Override
    public void run() {
      final String serviceName = AbstractService.this.getClass()
          .getSimpleName();
      Debug.info("Starting %s", serviceName);
      try {
        doStart();
        started = true;
      } catch (Exception e) {
        e.printStackTrace();
      } finally {
        latch.countDown();
        Debug.info("Done Starting %s", serviceName);
      }
    }
  }
}
import java.util.concurrent.CountDownLatch;


public class SampleServiceA extends AbstractService {

	public SampleServiceA(CountDownLatch latch) {
		super(latch);

	}

	@Override
	protected void doStart() throws Exception {
		// 模拟实际操作耗时
		Tools.randomPause(1000);

		// 省略其他代码
	}

}
import java.util.concurrent.CountDownLatch;

public class SampleServiceB extends AbstractService{
	
	public SampleServiceB(CountDownLatch latch) {
	  super(latch);
  }

	@Override
  public void doStart() throws Exception {
		// 模拟实际操作耗时
		Tools.randomPause(2000);
		
		// 省略其他代码
	  
  }

}
import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class SampleServiceC extends AbstractService {

	public SampleServiceC(CountDownLatch latch) {
		super(latch);
	}

	@Override
	public void doStart() throws Exception {
		// 模拟实际操作耗时
		Tools.randomPause(2000);
		
		// 省略其他代码

		// 模拟服务器启动失败
		final Random random = new Random();
		int rand = random.nextInt(1000);
		if (rand <= 500) {
			throw new RuntimeException("test");
		}
	}

}

猜你喜欢

转载自blog.csdn.net/u012895183/article/details/133269244