欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

优化Java线程实现类

程序员文章站 2022-05-31 14:21:26
...

多线程编程一方面比较复杂,另一方面运行出错后,难以定位等,所以针对对多线程实现的场景需要更谨慎,多关注编程实现的细节, 以便更好的实现和问题定位。

我们先来看一段实现Thread线程类的代码:

  public class ThreadTest {
      public static void main(String[] args) {
          new Thread() {
              @Override
              public void run() {
                  while (true) {
                      try {
                          Thread.sleep(1000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(getName() + ", do something...");
                  }
              }
          }.start();
          System.out.println("exit main...");
      }
  }

咋一看好像没什么问题,确实这段程序执行起来是没有什么大问题,但是仔细想一想程序是写给人看的,而且是由人维护的, 有更大的可能是你来实现,其他人来维护的,如果没问题还好,一旦有问题,再回过头来看代码和查找日志,都是个比较头疼的问题。

从代码维护角度来说,这段代码存在以下几个问题(当然不同的人理解不一样,有一些不见得是问题):

  • 未定义变量和匿名实现,不利于对象的回收和利用
  • 未设置为守护线程,主线程已停止,子线程还在后台执行
  • 未定义结束标识,线程循环执时无法在流程上友好地停止循环
  • 未设定明确的线程名,系统将自动分配线程名,然而在一个系统中往往会有很多个线程,如果都是这样,就无法确定哪个线程对应处理流程,特别是通过一些工具进行分析的时候,比如jconsole等
  • 无明确的初始化,启动,结束日志,一旦线程任意环节出现问题,缺少必要的日志,都给问题定位带来困扰。 线程实现定周期执行,使用线程Thread.sleep(long millis),实际线程资源并没有释放,不利于资源利用,比较好的方法定义一个锁对象,通过Object.wait(long millis) 进行资源释放

为解决以上问题,对Thread类做二次开发,具体如下:

public abstract class AbstractCycleThread extends AbstractThread {

      protected static final int STEP_WAITING = Integer.valueOf(1);

      protected static final int STEP_SOMETHING = Integer.valueOf(2);

      protected static final int STEP_NEXT_CONTINUE = Integer.valueOf(3);

      private volatile boolean cycle = true;

      private Object lock = new Object();

      private long waitTime = 0;

      public AbstractCycleThread(String threadName, long waitTime) {
          super(threadName);
          init(waitTime);
      }

      public AbstractCycleThread(long waitTime) {
          super(getFinalThreadName(AbstractCycleThread.class.getSimpleName()));
          init(waitTime);
      }

      private void init(long waitTime) {
          if (waitTime < 0) {
              this.waitTime = 0;
          } else {
              this.waitTime = waitTime;
          }
          info("init cycle thread, waitTime:" + waitTime);
      }

      @Override
      public void run() {
          info("start to run cycle thread:" + getName());
          int nextStep = STEP_WAITING;
          try {
              while (cycle) {
                  nextStep = beforeWaitingThenDoNextStep();
                  if (STEP_WAITING == nextStep) {
                      if (waitTime > 0) {
                          synchronized (lock) {
                              lock.wait(waitTime);
                          }
                      }
                      if (!afterWaitupThenDoSomething()) {
                          continue;
                      }
                  } else if (STEP_NEXT_CONTINUE == nextStep) {
                      continue;
                  }

                  // 执行业务操作
                  doSomething();
              }
          } catch (Exception e) {
              error("run cycle thread error:" + getName(), e);
              afterError();
              return;
          }
          info("finish to run cycle thread:" + getName());
          afterfinish();

      }

      /**
       * 执行lock.wait休眠等待前的处理操作
       * @return 

       *         

       *         {@link #STEP_WAITING} 进入休眠lock.wait等待
       *         

       *         {@link #STEP_NEXT_CONTINUE} 结束当前,进入下一次循环
       *         

       *         {@link #STEP_SOMETHING} 直接进入{@link #doSomething()}操作
       *         

       */
      protected int beforeWaitingThenDoNextStep() {
          // 可自行实现,默认进入等待
          return STEP_WAITING;
      }

      /**
       * 在{@link #beforeWaitingThenDoNextStep} 返回结果为{@link #STEP_WAITING}
       * 后,执行lock.wait休眠等待,等待结束后执行该方法,处理操作,默认不做任何处理,并返回true
       * 
       * @return 是否继续执行{@link #doSomething}操作
       */
      protected boolean afterWaitupThenDoSomething() {
          // 可自行实现,默认不做处理,直接返回下一步
          return true;
      }

      /**
       * 友好关闭线程
       * @see org.slive.thread.AbstractThread#stopFriendly()
       */
      public void stopFriendly() {
          if (!isAlive()) {
              return;
          }
          // 可自行实现
          // 唤醒后,设置循环标识为false
          synchronized (lock) {
              lock.notifyAll();
          }
          cycle = false;
      }
  }

测试:

public class CycleThreadTest {
      public static void main(String[] args) {
          long waitTime = 500;
          // 线程间数据共享
          List data = new ArrayList<>();
          MyCycleThread[] mcts = new MyCycleThread[5];
          for (int index = 0; index < mcts.length; index++) {
              mcts[index] = new MyCycleThread(waitTime, data);
              mcts[index].start();
          }
          
          int d = 1;
          int cycleTime = 0;
          while ((cycleTime++) < 50) {
              try {
                   // 更新数据共享的值
                  data.add(d++);
                  Thread.sleep(2000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
          // 优化关闭所有线程
          for (int index = 0; index < mcts.length; index++) {
              mcts[index].stopFriendly();
          }
      }

      static class MyCycleThread extends AbstractCycleThread {
          private List data;

          private List tempData = new ArrayList<>();

          public MyCycleThread(long waitTime, List data) {
              super(getFinalThreadName(MyCycleThread.class.getSimpleName()), waitTime);
              this.data = data;
          }

          @Override
          protected boolean afterWaitupThenDoSomething() {
              synchronized (data) {
                  if (!data.isEmpty()) {
                      // 如果有数据了,才继续后面的doSomething操作
                      tempData.addAll(data);
                      data.clear();
                      return true;
                  } else {
                      return false;
                  }
              }
          }

          @Override
          protected void doSomething() {
              Iterator ite = tempData.iterator();
              while (ite.hasNext()) {
                  System.out.println(System.currentTimeMillis() + " " + getName() + " do something value:" + ite.next());
                  ite.remove();
              }
          }
      }
  }
  

其它:

个人比较建议继承Thread类而不是实现Runnable接口,因为相对来说,Thread可实现的方法更多,更利于控制线程。

关于线程同步,资源共享,线程池等,与此次讨论的“优化Java线程类实现”并不冲突,处在不同的使用层次上,在此不展开讨论。

相关标签: 线程