前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java 程序驻留不退出保持运行

java 程序驻留不退出保持运行

作者头像
潇洒
发布2023-10-20 09:50:15
8040
发布2023-10-20 09:50:15
举报
文章被收录于专栏:石头岛

前言

不管是C、java、go 程序,要让程序一直不间断动行,就肯定需要保持线程不退出,才能可能持续运行。

今天说的是java,一般来说从main方法开始运行结束之后,线程也就退出,如何保证线程不退出? 实际上只要证保有一个线程在持续运行,程序就不算退出。 一般来说只需要保持main线程不退出,然后其他线程不间断的工作就OK。 实际上在如果开启多个线程,就算主线程执行结束了,子线程没有结整,JVM一样不会退出。

保持运行

上面说了,思路都量样的,就是阻塞一条线程,让JVM不要退出,一般是阻塞主线程main,让他阻塞不退出,直到需要退出的时候再限出。 演示几种不退出的方式:

  1. 读取流: System.in.read();
  2. 等待锁:
    • wait()
    • CountDownLatch(1).await();
  3. 死循环: while(true)
  4. 睡眠: sleep()

这几种方式,不是阻塞,就是睡眠,大概思路都差不多,就是

读取流

通过阻塞主线程,来验证一下,运行后就可以看到service的run方法执行完后,程序也不会退的。 代码可以自行复制验证。 这种方式可以用,一般线上服务都是通过kill -15来退出应用,即便是有流在等待读取,kill -15一样也会把服务kill掉。

代码语言:javascript
复制

import java.io.IOException;

/**
 * @author liukai
 * @since 2015/6/9.
 */
public class BlockTest {

  public static void main(String[] args) {

    new Thread(new Service()).start();

    try {
      System.in.read();

    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

class Service implements Runnable {

  @Override
  public void run() {
    for (int i = 0; i < 100000; i++) {
      try {
        System.out.println("service: " + i);
        Thread.sleep(200);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

线程等待

这个也好理解,就是让主线程wait,子线程工作。 上面的阻塞也是一样的原理。只要有一条线程没退出,jvm就还会继续工作。

代码语言:javascript
复制
public class BlockTest {

  private static Object object = new Object();
  public static void main(String[] args) {
    try {
      synchronized (object) {
        System.out.println("开始等待");
        object.wait();
        // 不会打印退出,可以在上面 wait 开一个子线程跑任务
        System.out.println("退出");
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

死循环

这种也非常简单,但是问题是有一条线程不停的自旋,这个效率肯定不如wait来的节约性能。当然电费不是自己交随意。 wait的原理是依赖于操作系统的阻塞队列,系统会检查线程状态,决定是否工作,这个后面可以专门说一下wait的r操作系统级别工作原理。 这种方式是相当的不推荐,那有没有办法,让程序可以在该阻塞的时候阻塞,该退出的时候退出,其实只能说方法还是有很多。再举个例子。

代码语言:javascript
复制

/**
 * @author liukai
 * @since 2016/6/9.
 */
public class BlockTest {

  public static void main(String[] args) {

    System.out.println("开始");
    // 开一个子线程跑任务
    new Thread(new Service()).start(); 
    while (true) {
      
    }
  }
}

可控制的退阻塞

这个名字我自己起的,因为确实是可控。JDK内置了很多工具,当然都以好好利用一下。 还是一样阻塞,再唤醒。使用JUC工具CountDownLatch加一个标识来控制,使用await使程阻塞,再需要的时候唤醒。 这种方式比较有效的控制线程的阻塞、运行状态给程序一个除了kill线程之外的另一个选择。我个从比较喜欢这种方式,虽然最后大部分时候退出程序都是使用的kill -15,但是写程序就是要预留出扩展性。

代码语言:javascript
复制
import java.util.concurrent.CountDownLatch;

/**
 * @author liukai
 * @since 2016/6/9.
 */
public class BlockTest {

  static CountDownLatch countDownLatch = new CountDownLatch(1);
  public static void main(String[] args) {
    System.out.println("开始");
    try {
      new Thread(new Service(countDownLatch)).start();
      countDownLatch.await();
      System.out.println("程序退出");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

class Service implements Runnable {
  private CountDownLatch countDownLatch;
  public Service(CountDownLatch countDownLatch) {
    this.countDownLatch = countDownLatch;
  }

  @Override
  public void run() {
    for (int i = 0; i < 100000; i++) {
      try {
        System.out.println("service: " + i);
        Thread.sleep(200);
        if (i == 50) {
          System.out.println("子线程调用 countDown");
          this.countDownLatch.countDown();
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

总结

以上就是几种保持程序不退出的方式,当然还有别的方法,上面几种方式,很多框架也使用,总的来说多了解一种多一个选择。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 保持运行
    • 读取流
    • 线程等待
    • 死循环
    • 可控制的退阻塞
    • 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档