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

前言:

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

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

Wait超时时间:

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

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

实例:



import java.util.Random;

public class TimeoutWaitExample {
  private static final Object lock = new Object();
  private static boolean ready = false;
  protected static final Random random = new Random();

  public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread() {
      @Override
      public void run() {
        for (;;) {
          synchronized (lock) {
            ready = random.nextInt(100) < 5 ? true : false;
            if (ready) {
              lock.notify();
            }
          }
          // 使当前线程暂停一段(随机)时间
          Tools.randomPause(500);
        }// for循环结束
      }
    };
    t.setDaemon(true);
    t.start();
    waiter(1000);
  }

  public static void waiter(final long timeOut) throws InterruptedException {
    if (timeOut < 0) {
      throw new IllegalArgumentException();
    }

    long start = System.currentTimeMillis();
    long waitTime;
    long now;
    synchronized (lock) {
      while (!ready) {
        now = System.currentTimeMillis();
        // 计算剩余等待时间
        waitTime = timeOut - (now - start);
        Debug.info("Remaining time to wait:%sms", waitTime);
        if (waitTime <= 0) {
          // 等待超时退出
          break;
        }
        lock.wait(waitTime);
      }// while循环结束

      if (ready) {
        // 执行目标动作
        guardedAction();
      } else {
        // 等待超时,保护条件未成立
        Debug.error("Wait timed out,unable to execution target action!");
      }
    }// 同步块结束
  }

  private static void guardedAction() {
    Debug.info("Take some action.");
    // ...
  }
}

基本流程讲解: 

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

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

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

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

其他代码:

import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Debug {
    private static ThreadLocal<SimpleDateFormat> sdfWrapper = new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        }

    };

    enum Label {
        INFO("INFO"),
        ERR("ERROR");
        String name;

        Label(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }

    // public static void info(String message) {
    // printf(Label.INFO, "%s", message);
    // }

    public static void info(String format, Object... args) {
        printf(Label.INFO, format, args);
    }

    public static void info(boolean message) {
        info("%s", message);
    }

    public static void info(int message) {
        info("%d", message);
    }

    public static void error(String message, Object... args) {
        printf(Label.ERR, message, args);
    }

    public static void printf(Label label, String format, Object... args) {
        SimpleDateFormat sdf = sdfWrapper.get();
        @SuppressWarnings("resource")
        final PrintStream ps = label == Label.INFO ? System.out : System.err;
        ps.printf('[' + sdf.format(new Date()) + "][" + label.getName()
                + "]["
                + Thread.currentThread().getName() + "]:" + format + " %n", args);
    }
}
import sun.misc.Unsafe;

import java.io.*;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

public final class Tools {
    private static final Random rnd = new Random();
    private static final Logger LOGGER = Logger.getAnonymousLogger();

    public static void startAndWaitTerminated(Thread... threads)
            throws InterruptedException {
        if (null == threads) {
            throw new IllegalArgumentException("threads is null!");
        }
        for (Thread t : threads) {
            t.start();
        }
        for (Thread t : threads) {
            t.join();
        }
    }

    public static void startThread(Thread... threads) {
        if (null == threads) {
            throw new IllegalArgumentException("threads is null!");
        }
        for (Thread t : threads) {
            t.start();
        }
    }

    public static void startAndWaitTerminated(Iterable<Thread> threads)
            throws InterruptedException {
        if (null == threads) {
            throw new IllegalArgumentException("threads is null!");
        }
        for (Thread t : threads) {
            t.start();
        }
        for (Thread t : threads) {
            t.join();
        }
    }

    public static void randomPause(int maxPauseTime) {
        int sleepTime = rnd.nextInt(maxPauseTime);
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    public static void randomPause(int maxPauseTime, int minPauseTime) {
        int sleepTime = maxPauseTime == minPauseTime ? minPauseTime : rnd
                .nextInt(maxPauseTime - minPauseTime) + minPauseTime;
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    public static Unsafe getUnsafe() {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            ((Field) f).setAccessible(true);
            return (Unsafe) f.get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void silentClose(Closeable... closeable) {
        if (null == closeable) {
            return;
        }
        for (Closeable c : closeable) {
            if (null == c) {
                continue;
            }
            try {
                c.close();
            } catch (Exception ignored) {
            }
        }
    }

    public static void split(String str, String[] result, char delimeter) {
        int partsCount = result.length;
        int posOfDelimeter;
        int fromIndex = 0;
        String recordField;
        int i = 0;
        while (i < partsCount) {
            posOfDelimeter = str.indexOf(delimeter, fromIndex);
            if (-1 == posOfDelimeter) {
                recordField = str.substring(fromIndex);
                result[i] = recordField;
                break;
            }
            recordField = str.substring(fromIndex, posOfDelimeter);
            result[i] = recordField;
            i++;
            fromIndex = posOfDelimeter + 1;
        }
    }

    public static void log(String message) {
        LOGGER.log(Level.INFO, message);
    }

    public static String md5sum(final InputStream in) throws NoSuchAlgorithmException, IOException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] buf = new byte[1024];
        try (DigestInputStream dis = new DigestInputStream(in, md)) {
            while (-1 != dis.read(buf))
                ;
        }
        byte[] digest = md.digest();
        BigInteger bigInt = new BigInteger(1, digest);
        String checkSum = bigInt.toString(16);

        while (checkSum.length() < 32) {
            checkSum = "0" + checkSum;
        }
        return checkSum;
    }

    public static String md5sum(final File file) throws NoSuchAlgorithmException, IOException {
        return md5sum(new BufferedInputStream(new FileInputStream(file)));
    }

    public static String md5sum(String str) throws NoSuchAlgorithmException, IOException {
        ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes("UTF-8"));
        return md5sum(in);
    }

    public static void delayedAction(String prompt, Runnable action, int delay/* seconds */) {
        Debug.info("%s in %d seconds.", prompt, delay);
        try {
            Thread.sleep(delay * 1000);
        } catch (InterruptedException ignored) {
        }
        action.run();
    }

    public static Object newInstanceOf(String className) throws InstantiationException,
            IllegalAccessException, ClassNotFoundException {
        return Class.forName(className).newInstance();
    }

}

参考文献:

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

猜你喜欢

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