• Java多线程编程- Wait等待超时控制


    前言:

    本文是基于《Java多线程编程实战指南》第五章个人理解,因为第五章内容很多,因此拆成了很多文章,源码是摘抄作者的源码,源码会加上自己的理解。

    读书笔记目前笔者正在更新如下, 《Java多线程编程实战指南-核心篇》,《How Tomcat Works》,再到《spring 源码》解读。

    Wait超时时间:

    Object.wait(long)允许我们制定一个超时时间(单位为毫秒),如果被暂停的等待线程在这个时间内没有被其他线程唤醒,那么Java虚拟机会自动唤醒该线程。

    不过Object.wait(long)既无返回值也不会抛出特定的异常,以便区分其返回是由于其他线程通知了当前线程还是由于等待超时。因此,使用Object.wait(long)的时候我们需要一些额外的处理。

    实例:

    1. import java.util.Random;
    2. public class TimeoutWaitExample {
    3. private static final Object lock = new Object();
    4. private static boolean ready = false;
    5. protected static final Random random = new Random();
    6. public static void main(String[] args) throws InterruptedException {
    7. Thread t = new Thread() {
    8. @Override
    9. public void run() {
    10. for (;;) {
    11. synchronized (lock) {
    12. ready = random.nextInt(100) < 5 ? true : false;
    13. if (ready) {
    14. lock.notify();
    15. }
    16. }
    17. // 使当前线程暂停一段(随机)时间
    18. Tools.randomPause(500);
    19. }// for循环结束
    20. }
    21. };
    22. t.setDaemon(true);
    23. t.start();
    24. waiter(1000);
    25. }
    26. public static void waiter(final long timeOut) throws InterruptedException {
    27. if (timeOut < 0) {
    28. throw new IllegalArgumentException();
    29. }
    30. long start = System.currentTimeMillis();
    31. long waitTime;
    32. long now;
    33. synchronized (lock) {
    34. while (!ready) {
    35. now = System.currentTimeMillis();
    36. // 计算剩余等待时间
    37. waitTime = timeOut - (now - start);
    38. Debug.info("Remaining time to wait:%sms", waitTime);
    39. if (waitTime <= 0) {
    40. // 等待超时退出
    41. break;
    42. }
    43. lock.wait(waitTime);
    44. }// while循环结束
    45. if (ready) {
    46. // 执行目标动作
    47. guardedAction();
    48. } else {
    49. // 等待超时,保护条件未成立
    50. Debug.error("Wait timed out,unable to execution target action!");
    51. }
    52. }// 同步块结束
    53. }
    54. private static void guardedAction() {
    55. Debug.info("Take some action.");
    56. // ...
    57. }
    58. }

    基本流程讲解: 

    1.初始化时候,构建一个静态对象Object

    2.创建了一个通知线程Thread t,是一个守护线程,并且for里面循环取值,random.nextInt,再100内取大于5的概率较大,所以是大概率位false,小概率位true

    3.所以主线程是在ready=falise的while循环里,并且停止在lock.wait,主线程进入waiting状态,等待时间需要扣除一部分代码到wait语句时间。

    4.最终当时间到达等待时间时间,再此判断ready条件,如果为true,则运行相应动作,如果不为true,则无法执行对应的动作。所以上述代码运行有两种结果,都有可能发生。

    其他代码:

    1. import java.io.PrintStream;
    2. import java.text.SimpleDateFormat;
    3. import java.util.Date;
    4. public class Debug {
    5. private static ThreadLocal sdfWrapper = new ThreadLocal() {
    6. @Override
    7. protected SimpleDateFormat initialValue() {
    8. return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    9. }
    10. };
    11. enum Label {
    12. INFO("INFO"),
    13. ERR("ERROR");
    14. String name;
    15. Label(String name) {
    16. this.name = name;
    17. }
    18. public String getName() {
    19. return name;
    20. }
    21. }
    22. // public static void info(String message) {
    23. // printf(Label.INFO, "%s", message);
    24. // }
    25. public static void info(String format, Object... args) {
    26. printf(Label.INFO, format, args);
    27. }
    28. public static void info(boolean message) {
    29. info("%s", message);
    30. }
    31. public static void info(int message) {
    32. info("%d", message);
    33. }
    34. public static void error(String message, Object... args) {
    35. printf(Label.ERR, message, args);
    36. }
    37. public static void printf(Label label, String format, Object... args) {
    38. SimpleDateFormat sdf = sdfWrapper.get();
    39. @SuppressWarnings("resource")
    40. final PrintStream ps = label == Label.INFO ? System.out : System.err;
    41. ps.printf('[' + sdf.format(new Date()) + "][" + label.getName()
    42. + "]["
    43. + Thread.currentThread().getName() + "]:" + format + " %n", args);
    44. }
    45. }
    1. import sun.misc.Unsafe;
    2. import java.io.*;
    3. import java.lang.reflect.Field;
    4. import java.math.BigInteger;
    5. import java.security.DigestInputStream;
    6. import java.security.MessageDigest;
    7. import java.security.NoSuchAlgorithmException;
    8. import java.util.Random;
    9. import java.util.logging.Level;
    10. import java.util.logging.Logger;
    11. public final class Tools {
    12. private static final Random rnd = new Random();
    13. private static final Logger LOGGER = Logger.getAnonymousLogger();
    14. public static void startAndWaitTerminated(Thread... threads)
    15. throws InterruptedException {
    16. if (null == threads) {
    17. throw new IllegalArgumentException("threads is null!");
    18. }
    19. for (Thread t : threads) {
    20. t.start();
    21. }
    22. for (Thread t : threads) {
    23. t.join();
    24. }
    25. }
    26. public static void startThread(Thread... threads) {
    27. if (null == threads) {
    28. throw new IllegalArgumentException("threads is null!");
    29. }
    30. for (Thread t : threads) {
    31. t.start();
    32. }
    33. }
    34. public static void startAndWaitTerminated(Iterable threads)
    35. throws InterruptedException {
    36. if (null == threads) {
    37. throw new IllegalArgumentException("threads is null!");
    38. }
    39. for (Thread t : threads) {
    40. t.start();
    41. }
    42. for (Thread t : threads) {
    43. t.join();
    44. }
    45. }
    46. public static void randomPause(int maxPauseTime) {
    47. int sleepTime = rnd.nextInt(maxPauseTime);
    48. try {
    49. Thread.sleep(sleepTime);
    50. } catch (InterruptedException e) {
    51. Thread.currentThread().interrupt();
    52. }
    53. }
    54. public static void randomPause(int maxPauseTime, int minPauseTime) {
    55. int sleepTime = maxPauseTime == minPauseTime ? minPauseTime : rnd
    56. .nextInt(maxPauseTime - minPauseTime) + minPauseTime;
    57. try {
    58. Thread.sleep(sleepTime);
    59. } catch (InterruptedException e) {
    60. Thread.currentThread().interrupt();
    61. }
    62. }
    63. public static Unsafe getUnsafe() {
    64. try {
    65. Field f = Unsafe.class.getDeclaredField("theUnsafe");
    66. ((Field) f).setAccessible(true);
    67. return (Unsafe) f.get(null);
    68. } catch (Exception e) {
    69. e.printStackTrace();
    70. }
    71. return null;
    72. }
    73. public static void silentClose(Closeable... closeable) {
    74. if (null == closeable) {
    75. return;
    76. }
    77. for (Closeable c : closeable) {
    78. if (null == c) {
    79. continue;
    80. }
    81. try {
    82. c.close();
    83. } catch (Exception ignored) {
    84. }
    85. }
    86. }
    87. public static void split(String str, String[] result, char delimeter) {
    88. int partsCount = result.length;
    89. int posOfDelimeter;
    90. int fromIndex = 0;
    91. String recordField;
    92. int i = 0;
    93. while (i < partsCount) {
    94. posOfDelimeter = str.indexOf(delimeter, fromIndex);
    95. if (-1 == posOfDelimeter) {
    96. recordField = str.substring(fromIndex);
    97. result[i] = recordField;
    98. break;
    99. }
    100. recordField = str.substring(fromIndex, posOfDelimeter);
    101. result[i] = recordField;
    102. i++;
    103. fromIndex = posOfDelimeter + 1;
    104. }
    105. }
    106. public static void log(String message) {
    107. LOGGER.log(Level.INFO, message);
    108. }
    109. public static String md5sum(final InputStream in) throws NoSuchAlgorithmException, IOException {
    110. MessageDigest md = MessageDigest.getInstance("MD5");
    111. byte[] buf = new byte[1024];
    112. try (DigestInputStream dis = new DigestInputStream(in, md)) {
    113. while (-1 != dis.read(buf))
    114. ;
    115. }
    116. byte[] digest = md.digest();
    117. BigInteger bigInt = new BigInteger(1, digest);
    118. String checkSum = bigInt.toString(16);
    119. while (checkSum.length() < 32) {
    120. checkSum = "0" + checkSum;
    121. }
    122. return checkSum;
    123. }
    124. public static String md5sum(final File file) throws NoSuchAlgorithmException, IOException {
    125. return md5sum(new BufferedInputStream(new FileInputStream(file)));
    126. }
    127. public static String md5sum(String str) throws NoSuchAlgorithmException, IOException {
    128. ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes("UTF-8"));
    129. return md5sum(in);
    130. }
    131. public static void delayedAction(String prompt, Runnable action, int delay/* seconds */) {
    132. Debug.info("%s in %d seconds.", prompt, delay);
    133. try {
    134. Thread.sleep(delay * 1000);
    135. } catch (InterruptedException ignored) {
    136. }
    137. action.run();
    138. }
    139. public static Object newInstanceOf(String className) throws InstantiationException,
    140. IllegalAccessException, ClassNotFoundException {
    141. return Class.forName(className).newInstance();
    142. }
    143. }

    参考文献:

    《Java多线程编程实战指南-核心篇》

  • 相关阅读:
    【力扣刷题】Day01——数组基础
    Metabase学习教程:系统管理-6
    【洛谷】P5020 货币系统
    HotReload For Unity的文档的导航的翻译,添加了一些自己的理解。很垃圾
    ubuntu 下C++程序利用Valgrind工具调试内存问题
    【每日一读】CoRGi: Content-Rich Graph Neural Networks with Attention
    大模型应用实战1——GLM4的原理与应用(用大模型做游戏npc制作)
    【Rust日报】2022-08-31 RustDesk 跻身 Rust 开源项目 Top 10 第九名
    Swift Combine 使用调试器调试管道 从入门到精通二十六
    app运行踩过的坑大赏
  • 原文地址:https://blog.csdn.net/u012895183/article/details/133174786