摘要

  • Java线程同步与异步
  • 线程池
  • 无锁化的实现方案
  • 分布式的实现方案

Java线程同步与异步

  • 1、同步相关的方法有:

    • wait、notify、notifyAll
  • 2、关键字:

    • Synchronized
  • 3、JDK锁框架

    • AQS(AbstractQueuedSynchronizer)
  • 4、AQS的实现类

    • java.util.concurrent.locks.ReentrantLock
    • java.util.concurrent.locks.ReentrantReadWriteLock
    • java.util.concurrent.CountDownLatch
    • java.util.concurrent.Semaphore
  • 5、例子:两个线程交替打印出100以内的奇数和偶数

public class SynchronizedTest{
    private static int cnt = 1;

    public static void main(String[] args){
        MyThread myThread = new MyThread();

        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);

        thread1.start();
        thread2.start();

        try{
            thread1.join();
            thread2.join();
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }

    priavte static class MyThread implements Runnable{
        @Override
        public void run(){
            while(true){
                synchronized(this){
                    this.notify();
                    if(cnt <=20){
                        String currentThreadName = Thread.currentThread().getName();
                        System.out.println(currentThreadName + ":" + cnt++);
                        try{
                            this.wait();
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }else{
                        return ;
                    }
                }
            }
        }
    }
}

输出结果: tuyi 还可以使用两种其他方法实现,加深自己对Java线程同步和互斥的理解!

线程池

  • 作用:控制线程并发数量,一般用在控制单机并发度上,也是实现流控的一种方案;
  • 实现原理:
    • 1、参数含义

      • corePoolSize:核心线程的数量,在CPU密集和IO密集型的任务中,这个参数的设置不太一样
      • maximumPoolSize:最大核心线程的数量
      • poolSize:当前线程的数量
    • 2、当用户向线程池中新提交一个线程的时候,会出现如下情况:

      • 如果当前线程池中线程的数量小于corePoolSize, 就会创建一个新的线程, 并添加到线程池中;
      • 如果当前线程池中线程的数量等于corePoolSize, 并且等待队列中还没有满,则把当前用户添加的线程对象放在等待队列中;
      • 如果当前线程池中线程的数量大于等于corePoolSize并且小于maximunPoolSize,并且等待队列已经满,则创建一个新的线程,并添加到线程池中;
      • 如果当前线程池中线程的数量等于maximunPoolSize, 则会根据线程创建线程时候的拒绝策略,进行相应的处理;
    • 3、Java线程对象中run方法和start方法区别:

      • 线程对象直接调用run方法,JVM是不会有感知,是不会直接产生一个新的线程, 此时程序运行的方式依然是串行的;
      • 线程对象直接调用start方法,JVM才会有感知,会产生一个新的线程, 此时才会产生并发多线程; 线程池正是充分利用了run方法和start的区别来实现线程的复用;

线程池的核心代码

public void execute(Runnable command){
    if(command == null)
        throw new NullPointerException();
    if(poolSize >= corPoolSize || !addIfUnderCorePoolSize(command)){
        if(runState == RUNNING && workQueue.offer(command)){
            if(runState != RUNNING || poolSize == 0)
                ensureQueuedTaskHandled(command);
        }
        else if(!addIfUnderMaxmumPoolSize(command))
            reject(command);
    }
}

图二

执行用户任务的核心代码:

图三

非常推荐阅读open in new window