From dce91d5d02e12548d78f63183433bd0d64326e9b Mon Sep 17 00:00:00 2001 From: fyang21117 <1135783636@qq.com> Date: Fri, 10 Jan 2020 19:52:14 +0800 Subject: [PATCH 1/5] add week_05/22/Thread-22.md. --- week_05/22/Thread-22.md | 222 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 week_05/22/Thread-22.md diff --git a/week_05/22/Thread-22.md b/week_05/22/Thread-22.md new file mode 100644 index 0000000..3c15dfe --- /dev/null +++ b/week_05/22/Thread-22.md @@ -0,0 +1,222 @@ +/** + * + * 2020年1月8日08:29:37 + * 【参考资料】 + * https://blog.csdn.net/u014730165/article/details/81980870 + * + * + * 【简介】 + * 线程作为资源调度的基本单位,是程序的执行单元,执行路径(单线程:一条执行路径,多线程:多条执行路径)。 + * 是程序使用CPU的最基本单位。 + * Java所有多线程的实现,均通过封装Thread类实现。 + */ + + + /**【构造函数】 + * Thread 的构造函数,采用缺省的方式实现 + */ + Thread(Runnable target) //传入Runnable接口实现 + Thread(Runnable target,String name) //接口+线程名 + Thread(ThreadGroup group,Runnable target) //设置当前线程用户组 + Thread(ThreadGroup group,Runnable target,String name) //用户组+接口+线程名 + Thread(ThreadGroup group,Runnable target,String name,long stackSize)//用户组+接口+线程名+当前线程栈大小 + + //1、线程默认名称生产规则:当前缺省线程名:“Thread-” + nextThreadNum() + public Thread(Runnable target){ + init(null,target,"Thread -"+ nextThreadNum(),0); + } + //nextThreadNum同步方法,线程安全,不会出现重复的threadInitNumber + private static int threadInitNumber; + private static synchronized int nextThreadNum(){ + return threadInitNumber++; + } + +/** + * Initializes a Thread. + * 2、线程私有化实现 + * + * @param g the Thread group + * @param target the object whose run() method gets called + * @param name the name of the new Thread + * @param stackSize the desired stack size for the new thread, or + * zero to indicate that this parameter is to be ignored. + * @param acc the AccessControlContext to inherit, or + * AccessController.getContext() if null + * @param inheritThreadLocals if {@code true}, inherit initial values for + * inheritable thread-locals from the constructing thread + */ + private void init(ThreadGroup g, Runnable target, String name,long stackSize, + AccessControlContext acc,boolean inheritThreadLocals) { + if (name == null) { + throw new NullPointerException("name cannot be null"); + } + this.name = name; + Thread parent = currentThread(); + SecurityManager security = System.getSecurityManager(); + + if (g == null) { + /* Determine if it's an applet or not */ + /* If there is a security manager, ask the security manager what to do. */ + if (security != null) { + g = security.getThreadGroup(); + } + /* If the security doesn't have a strong opinion of the matter use the parent thread group. */ + if (g == null) { + g = parent.getThreadGroup(); + } + } + /* checkAccess regardless of whether or not, threadgroup is explicitly passed in. */ + g.checkAccess(); + + if (security != null) { + if (isCCLOverridden(getClass())) { + security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); + } + } + + g.addUnstarted(); + this.group = g; + /* 设置当前线程是否为守护线程,默认是和当前类的ThreadGroup设置相同。如果是守护线程的话,当前线程结束会随着主线程的退出而退出。 + *jvm退出的标识是,当前系统没有活跃的非守护线程。 + */ + this.daemon = parent.isDaemon(); + /*设置线程的访问权限默认为当前ThreadGroup权限*/ + this.priority = parent.getPriority(); + if (security == null || isCCLOverridden(parent.getClass())) + this.contextClassLoader = parent.getContextClassLoader(); + else + this.contextClassLoader = parent.contextClassLoader; + this.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext(); + this.target = target; + setPriority(priority); + if (inheritThreadLocals && parent.inheritableThreadLocals != null) + this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); + /* Stash the specified stack size in case the VM cares */ + /*设置指定的栈大小,如果未指定大小,将在jvm 初始化参数中声明:Xss参数进行指定*/ + this.stackSize = stackSize; + /* Set thread ID */ + tid = nextThreadID(); + } + +/** + * 【start()方法源码分析】 + 导致此线程开始执行; Java Virtual Machine调用此线程的run方法。 + 结果是两个线程同时运行:当前线程(从调用返回到start方法)和另一个线程(执行其run方法)。 + 不止一次启动线程永远不合法。 + 特别是,一旦完成执行,线程可能无法重新启动。 + @exception IllegalThreadStateException如果线程已经启动。 + @see #run() + @see #stop()*/ + public synchronized void start() { + /** + * This method is not invoked for the main method thread or "system" group threads created/set up by the VM. + * Any new functionality added to this method in the future may have to also be added to the VM. + * A zero status value corresponds to state "NEW". + */ + //此判断当前线程只能被启动一次,不能被重复启动 + if (threadStatus != 0) + throw new IllegalThreadStateException(); + + /* Notify the group that this thread is about to be started so that it can be added to + the group's list of threads and the group's unstarted count can be decremented. */ + /*通知组该线程即将启动,这样它就可以添加到组的线程列表中,并且该组的未启动计数可以递减。*/ + group.add(this); + + boolean started = false; + try { + start0(); + started = true; + } finally { + try { + // 如果线程启动失败,从线程组里面移除该线程 + if (!started) { + group.threadStartFailed(this); + } + } catch (Throwable ignore) { + /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */ + } + } + } + +/** + * 【join()方法源码分析】 + * Waits at most {@code millis} milliseconds for this thread to die. A timeout of {@code 0} means to wait forever. + * + *

This implementation uses a loop of {@code this.wait} calls conditioned on {@code this.isAlive}. + * As a thread terminates the {@code this.notifyAll} method is invoked. It is recommended that + * applications not use {@code wait}, {@code notify}, or {@code notifyAll} on {@code Thread} instances. + * + * @param millis the time to wait in milliseconds + * + * @throws IllegalArgumentException if the value of {@code millis} is negative + * + * @throws InterruptedException if any thread has interrupted the current thread. + * The interrupted status of the current thread is cleared when this exception is thrown. + */ + public final synchronized void join(long millis) throws InterruptedException { + long base = System.currentTimeMillis(); + long now = 0; + if (millis < 0) { + throw new IllegalArgumentException("timeout value is negative"); + } + if (millis == 0) { // 如果millis == 0 线程将一直等待下去 + while (isAlive()) { + wait(0); + } + } else { // 指定了millis ,等待指定时间以后,会break当前线程 + while (isAlive()) { + long delay = millis - now; + if (delay <= 0) { + break; + } + wait(delay); + now = System.currentTimeMillis() - base; + } + } + } + +//Thread 内部枚举 State + public enum State { + + //尚未启动的线程的线程状态 + NEW, + /** + * 可运行线程的线程状态。 + * runnable中的一个线程 state正在Java虚拟机中执行但它可能正在执行 等待操作系统中的其他资源 如处理器。 + */ + RUNNABLE, + /** + * 线程阻塞等待监视器锁定的线程状态。(获取系统锁) + * 处于阻塞状态的线程正在等待监视器锁定,输入同步块/方法或,调用后重新输入同步块/方法 + */ + BLOCKED, + //处于等待状态的线程正在等待另一个线程*执行特定操作。 + WAITING, + /** + * 具有指定等待时间的等待线程的线程状态。 + * 由于使用指定的正等待时间调用以下方法之一,线程处于定时等待状态: + *

+ */ + TIMED_WAITING, + //终止线程的线程状态。线程已完成执行。 + TERMINATED; + } + +/*** + * 【run()方法:通过Java静态代理的方式实现】 + * Thread类重写了Runnable接口的run()方法。 + * 该run()方法首先判断当前是否有Runnable的实现target存在。 + * 如果存在就执行target.run()*/ +@Override +public void run() { + if (target != null) { + target.run(); + } +} + -- Gitee From 45ad71e873680d8df06646f09cc2321b85003e55 Mon Sep 17 00:00:00 2001 From: fyang21117 <1135783636@qq.com> Date: Fri, 10 Jan 2020 19:53:22 +0800 Subject: [PATCH 2/5] add week_05/22/ThreadPoolExecutor-22.md. --- week_05/22/ThreadPoolExecutor-22.md | 88 +++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 week_05/22/ThreadPoolExecutor-22.md diff --git a/week_05/22/ThreadPoolExecutor-22.md b/week_05/22/ThreadPoolExecutor-22.md new file mode 100644 index 0000000..9417ef1 --- /dev/null +++ b/week_05/22/ThreadPoolExecutor-22.md @@ -0,0 +1,88 @@ +/** + * + * 2020年1月8日08:29:37 + * 【参考资料】 + * https://mp.weixin.qq.com/s?__biz=Mzg2ODA0ODM0Nw==&mid=2247484026&idx=1&sn=fd4c456a504c0a51ffeee4f0292cdae3&scene=21#wechat_redirect + * + * 【简介】 + * ThreadPoolExecutor有四个构造方法,其中前三个最终都是调用最后一个,它有七个构造参数, + * 分别为corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。 + */ + +public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue) { +this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler); +} + +public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + ThreadFactory threadFactory) { +this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory, defaultHandler); +} + +public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + RejectedExecutionHandler handler) { +this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), handler); +} + +public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) + throw new IllegalArgumentException(); + if (workQueue == null || threadFactory == null || handler == null) + throw new NullPointerException(); + this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); + this.corePoolSize = corePoolSize; + this.maximumPoolSize = maximumPoolSize; + this.workQueue = workQueue; + this.keepAliveTime = unit.toNanos(keepAliveTime); + this.threadFactory = threadFactory; + this.handler = handler; +} + +/** + * + * 【corePoolSize】核心线程数。 +当正在运行的线程数小于核心线程数时,来一个任务就创建一个核心线程; +当正在运行的线程数大于或等于核心线程数时,任务来了先不创建线程而是丢到任务队列中。 + + * 【maximumPoolSize】最大线程数。 +当任务队列满了时,来一个任务才创建一个非核心线程,但不能超过最大线程数。 + + * 【keepAliveTime + unit】线程保持空闲时间及单位。 +默认情况下,此两参数仅当正在运行的线程数大于核心线程数时才有效,即只针对非核心线程。 +但是,如果allowCoreThreadTimeOut被设置成了true,针对核心线程也有效。 +即当任务队列为空时,线程保持多久才会销毁,内部主要是通过阻塞队列带超时的poll(timeout, unit)方法实现的。 + + * 【workQueue】任务队列。 +当正在运行的线程数大于或等于核心线程数时,任务来了是先进入任务队列中的。 +这个队列必须是阻塞队列,所以像ConcurrentLinkedQueue就不能作为参数,因为它虽然是并发安全的队列,但是它不是阻塞队列。 +1. // ConcurrentLinkedQueue并没有实现BlockingQueue接口 +2. public class ConcurrentLinkedQueue extends AbstractQueue implements Queue, java.io.Serializable {} + + * 【threadFactory】线程工厂。 +默认使用的是Executors工具类中的DefaultThreadFactory类,这个类创建的线程的名称是自动生成的,无法自定义以区分不同的线程池,且它们都是非守护线程。 + + * 【handler】拒绝策略。 +拒绝策略表示当任务队列满了且线程数也达到最大了,这时候再新加任务,线程池已经无法承受了,这些新来的任务应该按什么逻辑来处理。 +常用的拒绝策略有丢弃当前任务、丢弃最老的任务、抛出异常、调用者自己处理等待。 +默认的拒绝策略是抛出异常,即线程池无法承载了,调用者再往里面添加任务会抛出异常。 +默认的拒绝策略虽然比较简单粗暴,但是相对于丢弃任务策略明显要好很多,最起码调用者自己可以捕获这个异常再进行二次处理。 + + */ + -- Gitee From 356bdc6f34e5997b8713209d24b6a8cbc28247f1 Mon Sep 17 00:00:00 2001 From: fyang21117 <1135783636@qq.com> Date: Fri, 10 Jan 2020 19:54:09 +0800 Subject: [PATCH 3/5] add week_05/22/ThreadLocal-22.md. --- week_05/22/ThreadLocal-22.md | 218 +++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 week_05/22/ThreadLocal-22.md diff --git a/week_05/22/ThreadLocal-22.md b/week_05/22/ThreadLocal-22.md new file mode 100644 index 0000000..2ad6685 --- /dev/null +++ b/week_05/22/ThreadLocal-22.md @@ -0,0 +1,218 @@ +/** + * + * 2020年1月8日08:29:37 + * 【参考资料】 + * https://www.cnblogs.com/dennyzhangdd/p/7978455.html + * https://cloud.tencent.com/developer/article/1333298 + * http://tutorials.jenkov.com/java-concurrency/threadlocal.html + * https://droidyue.com/blog/2016/03/13/learning-threadlocal-in-java/ + * http://www.cnblogs.com/swiftma/p/6764821.html + * https://www.cnblogs.com/onlywujun/p/3524675.html + * + * 【简介】 + * ThreadLocalMap是一个定制的哈希映射,仅适用于维护线程本地值。ThreadLocalMap类是包私有的,允许在Thread类中声明字段。 + * 为了帮助处理非常大且长时间的使用,哈希表entry使用了对键的弱引用。有助于GC回收。 + * + * ThreadLocal类可理解为线程本地变量。定义一个ThreadLocal,每个线程往这个ThreadLocal中读写是线程隔离,互相之间不会影响。 + * 它提供了一种将可变数据通过每个线程有自己的独立副本从而实现线程封闭的机制。 + * + * 【threadLocal特性及使用场景】 + * 1、实现单个线程单例以及单个线程上下文信息存储,比如交易id等 + * 2、实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例 + * 3、承载一些线程相关的数据,避免在方法中来回传递参数 + */ + + +/** + * 【主要方法之一】 + * ThreadLocal的get方法 + * ThreadLocal之get流程: + 1、获取当前线程t; + 2、返回当前线程t的成员变量ThreadLocalMap(以下简写map); + 3、map不为null,则获取以当前线程为key的ThreadLocalMap的Entry(以下简写e),如果e不为null,则直接返回该Entry的value; + 4、如果map为null或者e为null,返回setInitialValue()的值。setInitialValue()调用重写的initialValue()返回新值 + (如果没有重写initialValue将返回默认值null),并将新值存入当前线程的ThreadLocalMap(如果当前线程没有ThreadLocalMap,会先创建一个)。 + */ +public T get() { + Thread t = Thread.currentThread(); + ThreadLocalMap map = getMap(t); + if (map != null) { + ThreadLocalMap.Entry e = map.getEntry(this); + if (e != null) { + @SuppressWarnings("unchecked") + T result = (T)e.value; + return result; + } + } + return setInitialValue(); + } + /** + * 【主要方法之二】 + * ThreadLocal的set方法 + ThreadLocal之set流程: + 1、获取当前线程t; + 2、返回当前线程t的成员变量ThreadLocalMap(以下简写map); + 3、map不为null,则更新以当前线程为key的ThreadLocalMap,否则创建一个ThreadLocalMap,其中当前线程t为key; + */ +public void set(T value) { + Thread t = Thread.currentThread(); + ThreadLocalMap map = getMap(t); + if (map != null) + map.set(this, value); + else + createMap(t, value); +} + + + /** + * 【主要代码解析】 + * ThreadLocals依赖于附加的每线程线性探测哈希映射到每个线程(Thread.threadLocals和 inheritableThreadLocals)。 + * ThreadLocal对象充当键,通过threadLocalHashCode搜索。这是一个自定义哈希码 (仅在ThreadLocalMaps内有用),可以消除哈希冲突。 + * 在连续构造ThreadLocals的常见情况下,由相同的线程使用,同时保持良好的行为和异常情况的发生。 + */ +public class ThreadLocal { + + private final int threadLocalHashCode = nextHashCode(); + //下一个哈希码将被发出,原子更新,从零开始。 + private static AtomicInteger nextHashCode = new AtomicInteger(); + //连续生成的散列码之间的区别 , 将隐式顺序线程本地ID转换为近乎最佳的散布 两倍大小的表的乘法散列值。 + private static final int HASH_INCREMENT = 0x61c88647; + private static int nextHashCode() { + return nextHashCode.getAndAdd(HASH_INCREMENT); + } + + /** + * 返回此线程局部变量的当前线程的“初始值”。 在线程首次访问带有{@link #get}方法的变量时,将调用此方法, + * 除非线程先前调用了{@link #set}方法,在这种情况下,initialValue方法不会 为该线程调用。 + * 通常,每个线程最多调用一次此方法,但在后续调用{@link #remove}后跟{@link #get}时可能会再次调用此方法。 + *

这个实现只是返回{@code null}; 如果程序员希望线程局部变量的初始值不是{@code null}, + * 则必须对子代码{@CodeLocal}进行子类化,并重写此方法。 通常,将使用匿名内部类。 + */ + protected T initialValue() { + return null; + } + public T get() { + Thread t = Thread.currentThread(); + ThreadLocalMap map = getMap(t); + if (map != null) { + ThreadLocalMap.Entry e = map.getEntry(this); + if (e != null) { + @SuppressWarnings("unchecked") + T result = (T)e.value; + return result; + } + } + return setInitialValue(); + } + private T setInitialValue() { + T value = initialValue(); + Thread t = Thread.currentThread(); + ThreadLocalMap map = getMap(t); + if (map != null) + map.set(this, value); + else + createMap(t, value); + return value; + } + public void set(T value) { + Thread t = Thread.currentThread(); + ThreadLocalMap map = getMap(t); + if (map != null) + map.set(this, value); + else + createMap(t, value); + } + + /** + * SuppliedThreadLocal是JDK8新增的内部类,只是扩展了ThreadLocal的初始化值的方法而已,允许使用JDK8新增的Lambda表达式赋值。 + * 需要注意的是,函数式接口Supplier不允许为null。 + */ + static final class SuppliedThreadLocal extends ThreadLocal { + private final Supplier supplier; + SuppliedThreadLocal(Supplier supplier) { + this.supplier = Objects.requireNonNull(supplier); + } + @Override + protected T initialValue() { + return supplier.get(); + } + } + /** + * ThreadLocalMap是定制的hashMap,仅用于维护当前线程的本地变量值。 + * 仅ThreadLocal类对其有操作权限,是Thread的私有属性。为避免占用空间较大或生命周期较长的数据常驻于内存引发一系列问题, + * hash table的key是弱引用WeakReferences。当空间不足时,会清理未被引用的entry。 + */ + static class ThreadLocalMap { + static class Entry extends WeakReference> { + /** The value associated with this ThreadLocal. */ + Object value; + Entry(ThreadLocal k, Object v) { + super(k); + value = v; + } + } + /** + * 构造一个新的包含初始映射,ThreadLocal映射的新映射,因此我们只在创建至少一个条目时创建一个。 + */ + ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { + table = new Entry[INITIAL_CAPACITY]; + int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); + table[i] = new Entry(firstKey, firstValue); + size = 1; + setThreshold(INITIAL_CAPACITY); + } + /** + * 从给定的parentMap构造一个包含所有map的新ThreadLocal。仅由createInheritedMap调用。 + * + * @param parentMap the map associated with parent thread. + */ + private ThreadLocalMap(ThreadLocalMap parentMap) { + Entry[] parentTable = parentMap.table; + int len = parentTable.length; + setThreshold(len); + table = new Entry[len]; + for (int j = 0; j < len; j++) { + Entry e = parentTable[j]; + if (e != null) { + @SuppressWarnings("unchecked") + ThreadLocal key = (ThreadLocal) e.get(); + if (key != null) { + Object value = key.childValue(e.value); + Entry c = new Entry(key, value); + int h = key.threadLocalHashCode & (len - 1); + while (table[h] != null) + h = nextIndex(h, len); + table[h] = c; + size++; + } + } + } + } + } +} + + +/** + * ThreadLocal 使用demo + */ +public class ThreadLocalExample { + public static class MyRunnable implements Runnable { + private ThreadLocal threadLocal =new ThreadLocal(); + @Override + public void run() { + threadLocal.set( (int) (Math.random() * 100D) ); + try { Thread.sleep(2000); + } catch (InterruptedException e) {} + System.out.println(threadLocal.get()); + } + } + public static void main(String[] args) { + MyRunnable sharedRunnableInstance = new MyRunnable(); + Thread thread1 = new Thread(sharedRunnableInstance); + Thread thread2 = new Thread(sharedRunnableInstance); + thread1.start(); + thread2.start(); + thread1.join(); //wait for thread 1 to terminate + thread2.join(); //wait for thread 2 to terminate + } +} \ No newline at end of file -- Gitee From 38bd4f365f655c5ae75bded0230129a65e0c6730 Mon Sep 17 00:00:00 2001 From: fyang21117 <1135783636@qq.com> Date: Fri, 10 Jan 2020 19:54:41 +0800 Subject: [PATCH 4/5] add week_05/22/Executors-22.md. --- week_05/22/Executors-22.md | 112 +++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 week_05/22/Executors-22.md diff --git a/week_05/22/Executors-22.md b/week_05/22/Executors-22.md new file mode 100644 index 0000000..94c3e4d --- /dev/null +++ b/week_05/22/Executors-22.md @@ -0,0 +1,112 @@ +/** + * + * 2020年1月8日08:29:37 + * 【参考资料】 + * https://cloud.tencent.com/developer/article/1442947 + * https://blog.csdn.net/z_s_z2016/article/details/81674893 + * + * 【简介】 + * Executors创建线程池的方式:根据返回的对象类型创建线程池可以分为三类: + * 创建返回ThreadPoolExecutor对象 + * 创建返回ScheduleThreadPoolExecutor对象 + * 创建返回ForkJoinPool对象 + * + * Executors的真正实现类主要包括两个ThreadPollExecutors和ScheduledThreadPoolExecutor。 + * 其中ScheduledThreadPoolExecutor通过实现其基类ScheduledExecutorService扩展了ThreadPoolExecutor类。 + * + * + * 【Executor线程池创建的四种线程】 + * (1)newFixedThreadPool:创建的是定长的线程池,可以控制线程最大并发数,超出的线程会在线程中等待, + * 使用的是无界队列,核心线程数和最大线程数一样,当线程池中的线程没有任务时候立刻销毁,使用默认线程工厂。 + * (2)newSingleThreadExecutor:创建的是单线程化的线程池,只会用唯一一个工作线程执行任务,可以指定按照是否是先入先出,还是优先级来执行任务。 + * 同样使用无界队列,核心线程数和最大线程数都是1个,同样keepAliveTime为0,可选择是否使用默认线程工厂。 + * (3)newCachedThreadPool:设定一个可缓存的线程池,当线程池长度超过处理的需要,可以灵活回收空闲线程,如果没有可以回收的才新建线程。 + * 没有核心线程数,当线程没有任务60s之后就会回收空闲线程,使用有界队列。同样可以选择是否使用默认线程工厂。 + * (4)newScheduledThreadPool:支持线程定时操作和周期性操作。 + */ + + +public class Executors { + /** + * 它是一种固定大小的线程池; + * corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads; + * keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效; + * 阻塞队列采用了LinkedBlockingQueue,它是一个无界队列; + * 由于阻塞队列是一个无界队列,因此永远不可能拒绝任务; + * 由于采用了无界队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。 + */ + public static ExecutorService newFixedThreadPool(int nThreads) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue()); + } + + + /** + * 它是一个可以无限扩大的线程池; + * 它比较适合处理执行时间比较小的任务; + * corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大; + * keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死; + * 采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他, + * 如果当前没有空闲的线程,那么就会再创建一条新的线程。 + */ + public static ExecutorService newSingleThreadExecutor() { + return new FinalizableDelegatedExecutorService + (new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue())); + } + + + /** + * 它只会创建一条工作线程处理任务; + * 采用的阻塞队列为LinkedBlockingQueue; + */ + public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { + return new FinalizableDelegatedExecutorService + (new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), + threadFactory)); + } + + + /** + * 【ScheduledThreadPool 可调度的线程池】 + * 它接收SchduledFutureTask类型的任务,有两种提交任务的方式: + * scheduledAtFixedRate + * scheduledWithFixedDelay + * + * 【SchduledFutureTask接收的参数:】 + * time:任务开始的时间 + * sequenceNumber:任务的序号 + * period:任务执行的时间间隔 + * + * 它采用DelayQueue存储等待的任务 + * DelayQueue内部封装了一个PriorityQueue,它会根据time的先后时间排序,若time相同则根据sequenceNumber排序; + * DelayQueue也是一个无界队列; + * + * 【工作线程的执行过程:】 + * 工作线程会从DelayQueue取已经到期的任务去执行; + * 执行结束后重新设置任务的到期时间,再次放回DelayQueue + */ + public static ExecutorService newCachedThreadPool() { + return new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue()); + } + public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { + return new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue(), + threadFactory); + } + + public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { + return new ScheduledThreadPoolExecutor(corePoolSize); + } + public static ScheduledExecutorService newScheduledThreadPool( + int corePoolSize, ThreadFactory threadFactory) { + return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); + } +} \ No newline at end of file -- Gitee From 89fd9e47ab05222986d5c3384728f8447b9b3efb Mon Sep 17 00:00:00 2001 From: fyang21117 <1135783636@qq.com> Date: Fri, 10 Jan 2020 19:55:33 +0800 Subject: [PATCH 5/5] add week_05/22/week05_leetcode-22.java. --- week_05/22/week05_leetcode-22.java | 188 +++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 week_05/22/week05_leetcode-22.java diff --git a/week_05/22/week05_leetcode-22.java b/week_05/22/week05_leetcode-22.java new file mode 100644 index 0000000..7221eda --- /dev/null +++ b/week_05/22/week05_leetcode-22.java @@ -0,0 +1,188 @@ +//【leetcode-1114按序打印 】 +//我们提供了一个类: +// public class Foo { +//   public void one() { print("one"); } +//   public void two() { print("two"); } +//   public void three() { print("three"); } +// } +// 三个不同的线程将会共用一个 Foo 实例。 +// 线程 A 将会调用 one() 方法 +// 线程 B 将会调用 two() 方法 +// 线程 C 将会调用 three() 方法 +// 请设计修改程序,以确保 two() 方法在 one() 方法之后被执行,three() 方法在 two() 方法之后被执行。 +// 示例 1: +// 输入: [1,2,3] +// 输出: "onetwothree" +// 解释: +// 有三个线程会被异步启动。 +// 输入 [1,2,3] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 two() 方法,线程 C 将会调用 three() 方法。 +// 正确的输出是 "onetwothree"。 +// 示例 2: +// 输入: [1,3,2] +// 输出: "onetwothree" +// 解释: +// 输入 [1,3,2] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 three() 方法,线程 C 将会调用 two() 方法。 +// 正确的输出是 "onetwothree"。 +// 注意: +// 尽管输入中的数字似乎暗示了顺序,但是我们并不保证线程在操作系统中的调度顺序。 +// 你看到的输入格式主要是为了确保测试的全面性。 +class Foo { + private boolean firstFinished; + private boolean secondFinished; + private Object lock = new Object(); + public Foo() { } + public void first(Runnable printFirst) throws InterruptedException { + synchronized (lock) { + // printFirst.run() outputs "first". Do not change or remove this line. + printFirst.run(); + firstFinished = true; + lock.notifyAll(); + } + } + public void second(Runnable printSecond) throws InterruptedException { + synchronized (lock) { + while (!firstFinished) { + lock.wait(); + } + // printSecond.run() outputs "second". Do not change or remove this line. + printSecond.run(); + secondFinished = true; + lock.notifyAll(); + } + } + public void third(Runnable printThird) throws InterruptedException { + synchronized (lock) { + while (!secondFinished) { + lock.wait(); + } + // printThird.run() outputs "third". Do not change or remove this line. + printThird.run(); + } + } +} + + +//【LeetCode-1115】 +// 我们提供一个类: +// class FooBar { +// public void foo() { +//     for (int i = 0; i < n; i++) { +//       print("foo"); +//   } +// } +// public void bar() { +//     for (int i = 0; i < n; i++) { +//       print("bar"); +//     } +// } +// } +// 两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。 +// 请设计修改程序,以确保 "foobar" 被输出 n 次。 +// 示例 1: +// 输入: n = 1 +// 输出: "foobar" +// 解释: 这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。 +// 示例 2: +// 输入: n = 2 +// 输出: "foobarfoobar" +// 解释: "foobar" 将被输出两次。 +//执行结果:通过显示详情(待优化) +//执行用时 :25 ms, 在所有 Java 提交中击败了23.46%的用户 +class FooBar { + private int n; + private volatile int flag = 0; + public FooBar(int n) { + this.n = n; + } + public void foo(Runnable printFoo) throws InterruptedException { + for (int i = 0; i < n; i++) { + while(flag != 0){ + Thread.yield(); + } + printFoo.run(); + flag = 1; + } + } + public void bar(Runnable printBar) throws InterruptedException { + for (int i = 0; i < n; i++) { + while(flag != 1){ + Thread.yield(); + } + printBar.run(); + flag = 0; + } + } +} + + +// LeetCode-1116打印零与奇偶数 +// 假设有这么一个类: +// class ZeroEvenOdd { +//   public ZeroEvenOdd(int n) { ... }  // 构造函数 +// public void zero(printNumber) { ... } // 仅打印出 0 +// public void even(printNumber) { ... } // 仅打印出 偶数 +// public void odd(printNumber) { ... } // 仅打印出 奇数 +// } +// 相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程: +// 线程 A 将调用 zero(),它只输出 0 。 +// 线程 B 将调用 even(),它只输出偶数。 +// 线程 C 将调用 odd(),它只输出奇数。 +// 每个线程都有一个 printNumber 方法来输出一个整数。请修改给出的代码以输出整数序列 010203040506... ,其中序列的长度必须为 2n。 +// 示例 1: +// 输入:n = 2 +// 输出:"0102" +// 说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),最后一个线程调用odd()。正确的输出为 "0102"。 +// 示例 2: +// 输入:n = 5 +// 输出:"0102030405" +class ZeroEvenOdd { + private int n; + private boolean ifZeroDone = false; + private boolean ifEvenOddDone = false; + public ZeroEvenOdd(int n) { + this.n = n; + } + // printNumber.accept(x) outputs "x", where x is an integer. + public void zero(IntConsumer printNumber) throws InterruptedException { + for (int i = 0; i < n; i++) { + synchronized (this) { + while (ifZeroDone) { + this.wait(); + } + printNumber.accept(0); + ifZeroDone = true; + this.notifyAll(); + } + } + } + public void even(IntConsumer printNumber) throws InterruptedException { + for (int j = 2; j <= n; j = j + 2) { + synchronized (this) { + while (!ifZeroDone || !ifEvenOddDone) { + this.wait(); + } + printNumber.accept(j); + ifZeroDone = false; + ifEvenOddDone = false; + this.notifyAll(); + } + } + } + public void odd(IntConsumer printNumber) throws InterruptedException { + for (int j = 1; j <= n; j = j + 2) { + synchronized (this) { + while (!ifZeroDone || ifEvenOddDone) { + this.wait(); + } + printNumber.accept(j); + ifZeroDone = false; + ifEvenOddDone = true; + this.notifyAll(); + } + } + } +} +//https://leetcode-cn.com/problemset/concurrency/ +//leetcode-1117 H20生成 +//leetcode-1195. 交替打印字符串 +//leetcode-1226. 哲学家进餐 \ No newline at end of file -- Gitee