From ab1959c03d320af24538b00d46ecb4e34b361662 Mon Sep 17 00:00:00 2001 From: "yutanbo123@163.com" Date: Sun, 12 Jan 2020 20:17:32 +0800 Subject: [PATCH 1/6] 007-Week 05 --- week_05/07/Thread.md | 100 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 week_05/07/Thread.md diff --git a/week_05/07/Thread.md b/week_05/07/Thread.md new file mode 100644 index 0000000..510a5cb --- /dev/null +++ b/week_05/07/Thread.md @@ -0,0 +1,100 @@ +Thread源码分析 +前言:Thread类实现了Runnable接口,实现的run()方法里调用了Runnable类的run()方法,如果不手动实现run()方法,则不会执行 +1.部分成员变量 + private volatile String name; //线程名称 + private boolean daemon = false; //守护线程 + private boolean stillborn = false; //JVM 状态 + private Runnable target; //线程接口 + private ThreadGroup group; //线程组 + private ClassLoader contextClassLoader; //类加载器 + private static int threadInitNumber; //初始化线程数 + private volatile int threadStatus = 0; //初始化线程状态 +2.构造方法 + //Thread类里的构造方法有9个,讲几个比较常用的 + //传入要执行的线程 + public Thread(Runnable target) { + init(null, target, "Thread-" + nextThreadNum(), 0); + } + //线程的名称 + public Thread(String name) { + init(null, null, name, 0); + } + //要执行的线程和名称 + public Thread(Runnable target, String name) { + init(null, target, name, 0); + } +3.常用的方法 + //这里面的方法有很多是native方法,就不分析源码了 + //sleep方法,这两个方法都是暂停线程的方法 + public static native void sleep(long millis) throws InterruptedException; + public static native void yield(); + //主要是这个run方法,子类一定要重写这个方法,如果不重写,就无法执行 + @Override + public void run() { + if (target != null) { + target.run(); + } + } + //start方法,启动线程需要调用这个方法,不能直接调用run,如果直接调用run,则跟调用普通的方法一样 + 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) //如果状态不为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(); //调用本地的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 */ + } + } + } + //等待其它线程执行完的方法 + 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) { //根据传入的时间,判断是否要增加超时等待 + while (isAlive()) { + wait(0); //调用Object的wait方法 + } + } else { + while (isAlive()) { + long delay = millis - now; + if (delay <= 0) { //增加时间判断,时间到了,也会停止等待 + break; + } + wait(delay); + now = System.currentTimeMillis() - base; + } + } + } +4.总结:Thread类是启动线程的一个入口,先重写run方法,再调用start启动线程 + + + + + + + + + -- Gitee From 735efafc27ad67694578b0eef6f256a24f7b2204 Mon Sep 17 00:00:00 2001 From: "yutanbo123@163.com" Date: Sun, 12 Jan 2020 21:10:38 +0800 Subject: [PATCH 2/6] 007-Week 05 --- week_05/07/1115-LeetCode.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 week_05/07/1115-LeetCode.md diff --git a/week_05/07/1115-LeetCode.md b/week_05/07/1115-LeetCode.md new file mode 100644 index 0000000..a9b183c --- /dev/null +++ b/week_05/07/1115-LeetCode.md @@ -0,0 +1,34 @@ +class FooBar { + private int n; + + volatile boolean flag = false; + public FooBar(int n) { + this.n = n; + } + + public void foo(Runnable printFoo) throws InterruptedException { + + for (int i = 0; i < n; i++) { + + // printFoo.run() outputs "foo". Do not change or remove this line. + while (flag) { + Thread.yield(); + } + printFoo.run(); + flag = true; + } + } + + public void bar(Runnable printBar) throws InterruptedException { + + for (int i = 0; i < n; i++) { + + // printBar.run() outputs "bar". Do not change or remove this line. + while (!flag) { + Thread.yield(); + } + printBar.run(); + flag = false; + } + } +} \ No newline at end of file -- Gitee From ec77723beef6b1b84bbccaf8138041395f5f77e3 Mon Sep 17 00:00:00 2001 From: "yutanbo123@163.com" Date: Sun, 12 Jan 2020 21:21:42 +0800 Subject: [PATCH 3/6] 007-Week 05 --- week_05/07/1116-LeetCode.md | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 week_05/07/1116-LeetCode.md diff --git a/week_05/07/1116-LeetCode.md b/week_05/07/1116-LeetCode.md new file mode 100644 index 0000000..1ef03f6 --- /dev/null +++ b/week_05/07/1116-LeetCode.md @@ -0,0 +1,40 @@ +class ZeroEvenOdd { + private int n; + + public ZeroEvenOdd(int n) { + this.n = n; + } + + Semaphore z = new Semaphore(1); + Semaphore e = new Semaphore(0); + Semaphore o = new Semaphore(0); + + // printNumber.accept(x) outputs "x", where x is an integer. + public void zero(IntConsumer printNumber) throws InterruptedException { + for (int i = 0; i < n; i++) { + z.acquire(); + printNumber.accept(0); + if ((i & 1) == 0) { + o.release(); + } else { + e.release(); + } + } + } + + public void even(IntConsumer printNumber) throws InterruptedException { + for (int i = 2; i <= n; i += 2) { + e.acquire(); + printNumber.accept(i); + z.release(); + } + } + + public void odd(IntConsumer printNumber) throws InterruptedException { + for (int i = 1; i <= n; i += 2) { + o.acquire(); + printNumber.accept(i); + z.release(); + } + } +} \ No newline at end of file -- Gitee From 3d76d01f9c22fec2281406db5155fa5c9c564948 Mon Sep 17 00:00:00 2001 From: "yutanbo123@163.com" Date: Sun, 12 Jan 2020 21:54:05 +0800 Subject: [PATCH 4/6] 007-Week 05 --- week_05/07/ThreadLocal.md | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 week_05/07/ThreadLocal.md diff --git a/week_05/07/ThreadLocal.md b/week_05/07/ThreadLocal.md new file mode 100644 index 0000000..e4db363 --- /dev/null +++ b/week_05/07/ThreadLocal.md @@ -0,0 +1,60 @@ +ThreadLocal源码分析 +前言:ThreadLocal类是一个本地线程副本变量工具类,可以将变量副本跟线程做一个映射,以达到各个线程之间变量的互不干扰 +1.成员变量 + private final int threadLocalHashCode = nextHashCode(); //线程的hashCode值 + private static AtomicInteger nextHashCode = + new AtomicInteger(); //int原子类 + private static final int HASH_INCREMENT = 0x61c88647; //没太搞清楚是干嘛的 +2.构造方法 + public ThreadLocal() { //是不是很纯粹,写了相当于没写,没写的话编译器会自动给生成一个 + } +3.常用方法 + //set方法 + public void set(T value) { + Thread t = Thread.currentThread(); //新建一个线程 + ThreadLocalMap map = getMap(t); //得到线程Map + if (map != null) // 如果Map不为空,把当前值设置到绑定的线程上 + map.set(this, value); + else + createMap(t, value); //如果为空,就创建一个 + } + //get方法 + public T get() { + Thread t = Thread.currentThread(); //当前线程 + ThreadLocalMap map = getMap(t); //得到当前线程Map + 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(); //下面跟set方法一样了 + ThreadLocalMap map = getMap(t); + if (map != null) + map.set(this, value); + else + createMap(t, value); + return value; + } + //remove方法 + public void remove() { //如果存在,把当前线程删除 + ThreadLocalMap m = getMap(Thread.currentThread()); + if (m != null) + m.remove(this); + } +4.总结:当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都有自己的独立变量,这也造成了内存增加 + + + + + + + + -- Gitee From 4ebe022852ece755fa8e5be57815ca3683b4406f Mon Sep 17 00:00:00 2001 From: "yutanbo123@163.com" Date: Sun, 12 Jan 2020 22:34:56 +0800 Subject: [PATCH 5/6] 007-Week 05 --- week_05/07/ThreadPoolExecutor.md | 111 +++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 week_05/07/ThreadPoolExecutor.md diff --git a/week_05/07/ThreadPoolExecutor.md b/week_05/07/ThreadPoolExecutor.md new file mode 100644 index 0000000..19a6519 --- /dev/null +++ b/week_05/07/ThreadPoolExecutor.md @@ -0,0 +1,111 @@ +ThreadPoolExecutor类源码分析 +前言:鉴于ThreadPoolExecutor类的源码比较多,我就分析几个主要的方法,其它的就不一一在这说了 +1.构造方法 + //总共有四个构造方法,分析参数最长的那个就行了,因为其它三个都是调用那一个 + 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) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + Executors.defaultThreadFactory(), defaultHandler); + } + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + RejectedExecutionHandler handler) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + Executors.defaultThreadFactory(), handler); + } + //先解释一下参数,corePoolSize 核心线程数,maximumPoolSize最大线程数(除核心线程外的非核心线程),keepAliveTime心跳时间,用来检查线程是否可以回收,unit时间单位,workQueue阻塞队列,当线程超过核心线程,会进入这个队列,threadFactory线程工厂,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; + } +2.主要方法 + public void execute(Runnable command) { + if (command == null) //任务为空,直接返回 + throw new NullPointerException(); + /* + * Proceed in 3 steps: + * + * 1. If fewer than corePoolSize threads are running, try to + * start a new thread with the given command as its first + * task. The call to addWorker atomically checks runState and + * workerCount, and so prevents false alarms that would add + * threads when it shouldn't, by returning false. + * + * 2. If a task can be successfully queued, then we still need + * to double-check whether we should have added a thread + * (because existing ones died since last checking) or that + * the pool shut down since entry into this method. So we + * recheck state and if necessary roll back the enqueuing if + * stopped, or start a new thread if there are none. + * + * 3. If we cannot queue task, then we try to add a new + * thread. If it fails, we know we are shut down or saturated + * and so reject the task. + */ + int c = ctl.get(); + if (workerCountOf(c) < corePoolSize) { //如果工作线程数量小于核心线程数量 + if (addWorker(command, true)) //增加核心线程 + return; + c = ctl.get(); + } + if (isRunning(c) && workQueue.offer(command)) { //如果达到了核心线程,新来的任务加入队列 + int recheck = ctl.get(); + if (! isRunning(recheck) && remove(command)) + reject(command); + else if (workerCountOf(recheck) == 0) //如果工作线程(核心线程)数量为0,就创建一个 + addWorker(null, false); + } + else if (!addWorker(command, false)) //如果队列满了,创建非核心工作线程 + reject(command); //如果非核心线程创建失败,执行拒绝策略 + } +4.总结:线程池还有很多的东西,先暂时说到这,欢迎大家补充 + + + + + + + + + + + + + + + -- Gitee From ca6a4aebcddf7da7b952e1b2a7551dc61bf7787a Mon Sep 17 00:00:00 2001 From: "yutanbo123@163.com" Date: Sun, 12 Jan 2020 22:55:55 +0800 Subject: [PATCH 6/6] 007-Week 05 --- week_05/07/Executors.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 week_05/07/Executors.md diff --git a/week_05/07/Executors.md b/week_05/07/Executors.md new file mode 100644 index 0000000..4a3b1a5 --- /dev/null +++ b/week_05/07/Executors.md @@ -0,0 +1,35 @@ +Executors源码分析 +前言:Executors是一个线程池工具类,可以快速的实现一个线程池 +1.构造方法 + /** Cannot instantiate. */ + private Executors() {} //就一个私有的构造方法,在外面是不能实例化的 +2.常用的方法 + //可以看到里面调用了ThreadPoolExecutor来实现的线程池方法,传入的参数为线程的数量 + public static ExecutorService newFixedThreadPool(int nThreads) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue()); + } + //这是上面方法的重载,多指定了线程工厂 + public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), + threadFactory); + } + //实现只有一个线程的线程池方法,指定线程工厂 + public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { + return new FinalizableDelegatedExecutorService + (new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), + threadFactory)); + } + //实现最大线程为Integer.MAX_VALUE的线程池,带有同步队列 + public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { + return new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue(), + threadFactory); + } +4.总结:还有带定时的线程池,项目中也没遇到过,所以这里就不讲了,如果有补充,欢迎指出 \ No newline at end of file -- Gitee