程序?进程?线程

线程

个数设置

线程个数:N= N U (1 + wait time / compute time)

状态

create

runnable

runnig

blocking / waiting

terminate

interrupt

interrupt

设置标记位

isInterrupt

查询是否可以被打断

interrupted

查询+重置标记位
wait sleep join一起使用会报错:interruptException
synchronized lock等获取锁的线程一起使用不会(ReentryLock可以使用LockInterruptly打断)

停止

自然结束

stop

执行后直接停止线程,不管线程在干嘛,如果恰巧在进行共享变量的属性赋值,则直接中断该过程

suspend/resume

如果线程正持有一把锁,则直接停止线程,不释放锁(类似于stop),容易造成死锁

volatile属性

不依赖于某个状态值时

interrupt

启动方式

  1. Thread
  2. Runnable
  3. lambda
  4. 线程池
  5. callable

并发三大特性

可见性(主存 & 本地内存)

解决方法

volatile

  • 修饰引用类型:只是引用本身可见,但是引用内部的数据不可见

    synchronized

    缓存行64bit(常见用long变量填充)

    cache line padding | @Contended + -XX:-RestrictContented

    why

    结果多次实践获得

  • 太大:内存命中率低,读取慢

  • 太小:读取次数多,性能低

    MESI(缓存一致性协议intel x86)

  1. modified
  2. Exclusive
  3. Shared
  4. Invalid

    有序性

    as-if-serial

    在单线程中,如果不影响查询最后的一致性那么cpu就会对程序进行一定的重排序

    原子性

    increment

    synchronized

    atomic

    自旋

    longaddr

    分段锁

    synchronized(blocked)=>系统锁=>执行时间长,线程数多

    支持可重入锁,当发生异常的时候会自动释放锁

    可重入锁:一个对象获得某种类型的锁后(还在使用)还可以获得该类锁

  1. package multiThreading;
  2. import java.util.concurrent.TimeUnit;
  3. /**
  4. * Created by Intellij IDEA.
  5. *
  6. * @author JonnyJiang
  7. * @date 2021/8/4
  8. */
  9. public class SynchronizedState {
  10. public static void main(String[] args) throws InterruptedException {
  11. SynchronizedState synchronizedState = new SynchronizedState();
  12. Thread thread1 = new Thread(()-> {
  13. try {
  14. synchronizedState.m1();
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. });
  19. Thread thread2 = new Thread(()-> {
  20. try {
  21. synchronizedState.m2();
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. }
  25. });
  26. thread1.start();
  27. TimeUnit.SECONDS.sleep(1);
  28. thread2.start();
  29. TimeUnit.SECONDS.sleep(1);
  30. System.out.println(thread2.getState());
  31. }
  32. public synchronized void m1() throws InterruptedException {
  33. System.out.println(Thread.currentThread().getState());
  34. TimeUnit.SECONDS.sleep(10);
  35. }
  36. public synchronized void m2() throws InterruptedException {
  37. System.out.println(Thread.currentThread().getState());
  38. TimeUnit.SECONDS.sleep(10);
  39. }
  40. }

lock(自旋=>waiting)=>用户锁=>执行时间短,线程数少

  1. package multiThreading;
  2. import java.util.concurrent.TimeUnit;
  3. import java.util.concurrent.locks.Lock;
  4. import java.util.concurrent.locks.ReentrantLock;
  5. /**
  6. * Created by Intellij IDEA.
  7. *
  8. * @author JonnyJiang
  9. * @date 2021/8/4
  10. */
  11. public class LockState {
  12. public static void main(String[] args) throws InterruptedException {
  13. Lock lock = new ReentrantLock();
  14. Thread thread1 = new Thread(()->{
  15. try{
  16. lock.lock();
  17. for (;;){
  18. }
  19. }catch (Exception e){
  20. }finally {
  21. lock.unlock();
  22. }
  23. });
  24. Thread thread2 = new Thread(()->{
  25. try{
  26. lock.lock();
  27. for(;;){
  28. }
  29. }catch (Exception e){
  30. }finally {
  31. }
  32. });
  33. thread1.start();
  34. TimeUnit.SECONDS.sleep(1);
  35. thread2.start();
  36. TimeUnit.SECONDS.sleep(1);
  37. System.out.println(thread2.getState());
  38. }
  39. }

ReentryLock

CountDownLatch(类似于批处理的thead.join(),只可以使用一次)

  1. package multiThreading;
  2. import java.util.concurrent.CountDownLatch;
  3. /**
  4. * Created by Intellij IDEA.
  5. *
  6. * @author JonnyJiang
  7. * @date 2021/8/3
  8. */
  9. public class CountDownLatchDemo {
  10. public static void main(String[] args) {
  11. CountDownLatch countDownLatch = new CountDownLatch(100);
  12. Thread[] threads = new Thread[100];
  13. for (int i = 0; i < threads.length; i++) {
  14. threads[i] = new Thread(()->{
  15. System.out.println(Thread.currentThread().getName());
  16. countDownLatch.countDown();
  17. });
  18. }
  19. for(Thread t:threads){
  20. t.start();
  21. }
  22. try{
  23. countDownLatch.await();
  24. }catch (Exception e){
  25. e.printStackTrace();
  26. }finally {
  27. System.out.println("end latch");
  28. }
  29. }
  30. }

CyclicBarrier(等指定数量的线程执行完了后才放行,可以使用多次,多批次)

  1. package multiThreading;
  2. import java.util.concurrent.BrokenBarrierException;
  3. import java.util.concurrent.CyclicBarrier;
  4. /**
  5. * Created by Intellij IDEA.
  6. *
  7. * @author JonnyJiang
  8. * @date 2021/8/3
  9. */
  10. public class CyclicBarrierDemo {
  11. public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
  12. // 每次等待20个线程
  13. CyclicBarrier cyclicBarrier = new CyclicBarrier(20,()->{
  14. System.out.println("go go go");
  15. });
  16. Thread[] threads = new Thread[100];
  17. for (int i = 0; i < threads.length; i++) {
  18. threads[i] = new Thread(()->{
  19. try {
  20. cyclicBarrier.await();
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. } catch (BrokenBarrierException e) {
  24. e.printStackTrace();
  25. }
  26. });
  27. }
  28. for(Thread t:threads){
  29. t.start();
  30. }
  31. System.out.println("end");
  32. }
  33. }

phaser(跟cyclicbarrier很相似,只不过是可以具体的分不同的阶段,以及可以很方便的增加一些筛选条件)

  1. package multiThreading;
  2. import java.util.concurrent.*;
  3. /**
  4. * Created by Intellij IDEA.
  5. *
  6. * @author JonnyJiang
  7. * @date 2021/8/4
  8. */
  9. public class PhaserDemo {
  10. public static void main(String[] args) {
  11. MyPhaser myPhaser = new MyPhaser();
  12. Thread[] threads = new Thread[]{new Thread(new Person(myPhaser,"张三"),"张三"), new Thread(new Person(myPhaser,"李四"),"李四"),new Thread(new Person(myPhaser,"王五"),"王五")};
  13. for (Thread t:threads){
  14. t.start();
  15. }
  16. }
  17. }
  18. class MyPhaser extends Phaser {
  19. @Override
  20. protected boolean onAdvance(int phase, int registeredParties) {
  21. switch (phase){
  22. case 0:
  23. System.out.println("walk"+registeredParties);
  24. return false;
  25. case 1:
  26. System.out.println("go"+registeredParties);
  27. return false;
  28. case 2:
  29. System.out.println("stop"+registeredParties);
  30. return false;
  31. default:
  32. System.out.println("end");
  33. return true;
  34. }
  35. }
  36. }
  37. class Person implements Runnable{
  38. private MyPhaser myPhaser = null;
  39. private String name = null;
  40. public Person(MyPhaser myPhaser, String name){
  41. this.myPhaser = myPhaser;
  42. this.myPhaser.register();
  43. this.name = name;
  44. }
  45. @Override
  46. public void run() {
  47. walk();
  48. go();
  49. stop();
  50. }
  51. public void walk(){
  52. System.out.println("走:"+Thread.currentThread().getName());
  53. this.myPhaser.arriveAndAwaitAdvance();
  54. }
  55. public void go(){
  56. System.out.println("跑:"+Thread.currentThread().getName());
  57. this.myPhaser.arriveAndAwaitAdvance();
  58. }
  59. public void stop(){
  60. if(!this.name.equals("张三")){
  61. this.myPhaser.arriveAndAwaitAdvance();
  62. }
  63. System.out.println("停止了"+Thread.currentThread().getName());
  64. }
  65. }

ReentrantReadWriteLock

  1. package multiThreading;
  2. import java.time.LocalDate;
  3. import java.util.Random;
  4. import java.util.concurrent.TimeUnit;
  5. import java.util.concurrent.locks.Lock;
  6. import java.util.concurrent.locks.ReentrantLock;
  7. import java.util.concurrent.locks.ReentrantReadWriteLock;
  8. /**
  9. * Created by Intellij IDEA.
  10. *
  11. * @author JonnyJiang
  12. * @date 2021/8/5
  13. */
  14. public class ReadWriteLockDemo {
  15. private static int value = 0;
  16. public static void main(String[] args) {
  17. Lock reentrantLockW = new ReentrantLock();
  18. Lock reentrantLockR = new ReentrantLock();
  19. ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
  20. ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
  21. ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
  22. Runnable readR = ()->read(readLock);
  23. Runnable readW = ()->write(writeLock, new Random().nextInt(100));
  24. for(int i = 0;i<10;i++){
  25. new Thread(readR).start();
  26. }
  27. for (int i = 0; i < 2; i++) {
  28. new Thread(readW).start();
  29. }
  30. }
  31. public static void read(Lock lock){
  32. try{
  33. lock.lock();
  34. System.out.println("read over\t"+value);
  35. Thread.sleep(1000);
  36. }catch (Exception e){
  37. e.printStackTrace();
  38. }finally {
  39. lock.unlock();
  40. }
  41. }
  42. public static void write(Lock lock,int newValue){
  43. try{
  44. lock.lock();
  45. value = newValue;
  46. System.out.println("write over");
  47. Thread.sleep(1000);
  48. }catch (Exception e){
  49. e.printStackTrace();
  50. }finally {
  51. lock.unlock();
  52. }
  53. }
  54. }

LockSupport(可以自定义阻塞锁(waiting))

  1. package multiThreading;
  2. import java.sql.Timestamp;
  3. import java.util.concurrent.TimeUnit;
  4. import java.util.concurrent.locks.LockSupport;
  5. /**
  6. * Created by Intellij IDEA.
  7. *
  8. * @author JonnyJiang
  9. * @date 2021/8/5
  10. */
  11. public class LockSupportDemo {
  12. public static void main(String[] args) throws InterruptedException {
  13. Thread thread = new Thread(()->{
  14. for (int i = 0; i < 100; i++) {
  15. if(i == 5){
  16. LockSupport.park();
  17. System.out.println("t当前时间:"+ System.currentTimeMillis() /1000);
  18. }
  19. System.out.println(i);
  20. try {
  21. TimeUnit.SECONDS.sleep(1);
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. });
  27. thread.start();
  28. TimeUnit.SECONDS.sleep(2);
  29. // 若在park前执行unpark会导致park无效
  30. LockSupport.unpark(thread);
  31. // System.out.println("当前时间:"+ System.currentTimeMillis() / 1000);
  32. }
  33. }

锁的升级

无锁

偏向锁

markword 中记录了执行线程的id,此时没有其他线程竞争

轻量级锁(自旋)

当有其他线程竞争时,就会进入自旋等待锁的释放,自旋超过10次后进入重量级锁

重量级锁

进入os获取锁的资源

volatile

可见性

硬件层面保证数据一致性

锁总线

MESI

  1. modified
  2. exclusive
  3. shared
  4. invalid

    有序性(禁止指令重排序)

    CAS(compare and swap)

    过程为cpu级别不可中断

    使用

    cas(V,expected,newValue)

    问题:

    ABA

    获取的值和最初值一样,但是中间可能发生了某些改变。比如说:1 -> 2 -> 1

    解决方法:

    加版本号

    引用

    就普通的引用,当引用指向为null时,原被指向的内存才会被回收 ```java package multiThreading;

/**

  • Created by Intellij IDEA. *
  • @author JonnyJiang
  • @date 2021/8/5 */ public class StrongReference { public static void main(String[] args) {
    1. M m = new M();
    2. m = null;
    3. System.gc();
    } }

class M{ @Override protected void finalize() { System.out.println(“finalize被执行”); } }

  1. <a name="6FQSI"></a>
  2. ## 软
  3. 当内存不足时才会被gc回收
  4. > 在运行时加上jvm参数:-Xms10M -Xmx10M
  5. ```java
  6. package multiThreading;
  7. import java.lang.ref.SoftReference;
  8. /**
  9. * Created by Intellij IDEA.
  10. *
  11. * @author JonnyJiang
  12. * @date 2021/8/5
  13. */
  14. public class SoftReferenceDemo {
  15. public static void main(String[] args){
  16. SoftReference softReference = new SoftReference<>(new M());
  17. System.out.println(softReference.get());
  18. System.gc();
  19. System.out.println(softReference.get());
  20. byte[] bytes = new byte[1024*1024*7 - 1024*680]; // 设置过大就会报OOM,过小就不会触发fgc
  21. System.out.println(softReference.get());
  22. }
  23. }

image.png

只要gc就会被回收,常用于threadlocal

package multiThreading;

import java.lang.ref.WeakReference;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/5
 */
public class WeakReferenceDemo {
    public static void main(String[] args) {
        WeakReference weakReference = new WeakReference<>(new M());
        System.out.println(weakReference.get());
        System.gc();
        System.out.println(weakReference.get());
        System.out.println(weakReference.get());
    }
}

结果:
image.png
image.png
因为在使用threadlocal.set(k,v)时,k=>threadlocal,如果threadlocal指向空,那么threadlocalMap中的key就会造成内存泄漏,久而久之就会造成oom,因此在设计ThreadLocalMap时,它的entry就是设计成weakReference,当发生gc时才会被回收

注意:

使用完了一定要remove,防止造成上述的内存泄漏

形同虚设,根据官方文档解释,在被回收时会将对象放入队列中:

Phantom reference objects, which are enqueued after the collector determines that their referents may otherwise be reclaimed. Phantom references are most often used for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism. If the garbage collector determines at a certain point in time that the referent of a phantom reference is phantom reachable, then at that time or at some later time it will enqueue the reference. In order to ensure that a reclaimable object remains so, the referent of a phantom reference may not be retrieved: The get method of a phantom reference always returns null. Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.

上代码:

package multiThreading;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/5
 */
public class PhantomReferenceDemo {
    public static void main(String[] args) throws InterruptedException {

        ReferenceQueue referenceQueue = new ReferenceQueue();
        PhantomReference phantomReference = new PhantomReference<Object>(new M(), referenceQueue);
        phantomReference.enqueue();
        System.out.println(phantomReference.get());
        System.out.println(referenceQueue.poll());
    }
}

image.png
大多数用与NIO中记录直接内存(堆外内存)的地址,用于记录被回收的对象的信息,方便以后回收堆外内存

常见的容器

容器.jpg

LinkedBlockingQueue

package multiThreading;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class LinkedBlockingQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue blockingQueue = new LinkedBlockingQueue<>();
        // 阻塞
        System.out.println(blockingQueue.take());
        // 空
        System.out.println(blockingQueue.poll());
       // 报错
        System.out.println(blockingQueue.remove());
    }
}

ArrayBlockingQueue

package multiThreading;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class ArrayBlockingQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(2);
        for (int i = 0; i < 5; i++) {
            // 阻塞
            blockingQueue.put(i);
            // 报错
            blockingQueue.add(i);
            // 不能添加
            System.out.println(blockingQueue.offer(i));
        }
    }
}

PriorityDeque

package multiThreading;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class PriorityBlockingQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<Integer> blockingQueue = new PriorityBlockingQueue();
        blockingQueue.put(2);
        blockingQueue.put(1);
        System.out.println(blockingQueue);
    }

}

DelayQueue

package multiThreading;

import com.mysql.cj.jdbc.MysqlDataSource;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class DelayQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<MyTask> blockingQueue = new DelayQueue<>();
        blockingQueue.put(new MyTask("a", 1000));
        blockingQueue.put(new MyTask("b",500));
        for (MyTask myTask : blockingQueue) {
            System.out.println(myTask);
        }

    }

    static class MyTask implements Delayed{

        private String name;
        private long time;

        public MyTask(String name, long time){
            this.name = name;
            this.time = time;
        }

        public String getName(){
            return this.name;
        }

        public long getTime(){
            return this.time;
        }
        @Override
        public long getDelay(TimeUnit unit) {
            return unit.toNanos(time);
        }

        @Override
        public int compareTo(Delayed o) {
            if(this.time < ((MyTask)o).getTime()){
                return -1;
            }else if(this.time > ((MyTask)o).getTime()){
                return 1;
            }else {
                return 0;
            }
        }

        @Override
        public String toString() {
            return "MyTask{" +
                    "name='" + name + '\'' +
                    ", time=" + time +
                    '}';
        }
    }
}

SynchronousQueue

package multiThreading;

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * Created by Intellij IDEA.
 *  SynchronousQueue:要求必须先有消费者准备着,然后将元素放入队列中,元素才会被拿,否则一直被阻塞,确保队列中的元素被所有
 *      消费者使用完
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class SynchronousQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        SynchronousQueue<Integer> synchronousQueue = new SynchronousQueue<>();
        new Thread(()->{
            try {
                while (true){
                    System.out.println("到我表演了:"+synchronousQueue.take());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        TimeUnit.SECONDS.sleep(1);

        synchronousQueue.put(1);
        synchronousQueue.put(2);


    }
}

LinkedTransferQueue

package multiThreading;

import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TimeUnit;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class TransferQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        LinkedTransferQueue<Integer> blockingQueue = new LinkedTransferQueue<>();

        new Thread(()->{
            try {
                System.out.println("开始表演:"+blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
//        System.out.println(blockingQueue.take());
        TimeUnit.SECONDS.sleep(1);
        blockingQueue.put(1);
        blockingQueue.put(2);
        System.out.println(blockingQueue.size());
//        System.out.println(blockingQueue.take());
    }
}

交替打印实现

synchronize+wait/notify

package multiThreading;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class AlternatePrint {
    static final Object lock = new Object();

    public static void main(String[] args) {
        char[] aI = "123456789".toCharArray();
        char[] aC = "ABCDEFGHI".toCharArray();

        new Thread(()->{
            synchronized (lock){
                for(char c:aI){
                    try {
                        System.out.print(c);
                        lock.wait();
                        lock.notify();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        new Thread(()->{
            synchronized (lock){
                for(char c:aC){
                    try {
                        System.out.print(c);
                        lock.notify();
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

volatile + 自旋

package multiThreading;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class AlternatePrint {
    static final Object lock = new Object();
    // 先打印数字,在打印字母
    static volatile boolean pI = true;
    static volatile boolean pC = false;

    public static void main(String[] args) {
        char[] aI = "123456789".toCharArray();
        char[] aC = "ABCDEFGHI".toCharArray();

        // 打印数字
        new Thread(()->{
            for(char c:aI){
                if (pI){
                    System.out.print(c);
                    pI = false;
                    pC = true;
                }
                for(;!pI && c != aI[aI.length - 1];){}

            }
        }).start();

        // 打印字母
        new Thread(()->{
            for(char c:aC){
                if (pC){
                    System.out.print(c);
                    pI = true;
                    pC = false;
                }
                for(;!pC && c != aC[aC.length - 1];){}
            }
        }).start();
    }
}

ReentrantLock

注意:wait/notify 不能和reentrantLock一起使用,只能结合synchronized使用,可以通过使用reentrantLock的await/signal来代替

package multiThreading;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class AlternatePrint {

    static final Lock LOCK = new ReentrantLock();
    static final Condition CONDITION = LOCK.newCondition();

    public static void main(String[] args) {
        char[] aI = "123456789".toCharArray();
        char[] aC = "ABCDEFGHI".toCharArray();

        new Thread(()->{
            try{
                LOCK.lock();
                for (char c:aI){
                    System.out.print(c);
                    CONDITION.await();
                    CONDITION.signal();
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                LOCK.unlock();
            }

        }).start();

        new Thread(()->{
            try{
                LOCK.lock();
                for (char c:aC){
                    System.out.print(c);
                    CONDITION.signal();
                    CONDITION.await();
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                LOCK.unlock();
            }
        }).start();
    }
}

LockSupport

package multiThreading;

import java.util.concurrent.locks.LockSupport;


/**
 * Created by Intellij IDEA.
 *
 * @author JonnyJiang
 * @date 2021/8/6
 */
public class AlternatePrint {
    static Thread T1 = null;
    static Thread T2 = null;

    public static void main(String[] args) {
        char[] aI = "123456789".toCharArray();
        char[] aC = "ABCDEFGHI".toCharArray();



        T1 = new Thread(()->{
            for(char c:aI){
                System.out.print(c);
                LockSupport.unpark(T2);
                LockSupport.park();
            }
            LockSupport.unpark(T2);
        });

        T2 = new Thread(()->{
            // 保证数字先打印
            LockSupport.park();
            for(char c:aC){
                System.out.print(c);
                LockSupport.unpark(T1);
                LockSupport.park();
            }
            LockSupport.unpark(T1);
        });

        T1.start();
        T2.start();
    }
}

线程池

拒绝策略

jdk提供了四种。还可以自定义

abort

报错

discard

扔掉

discardOldest

扔掉最老的

CallerRuns

调用者处理任务