当前位置: 首页>后端>正文

多线程和高并发知识梳理

多线程与高并发

线程

什么是线程

  • 进程

    进程相对于可执行程序来说是一个动态概念,比如磁盘上有一个QQ.exe程序,双击运行就是一个进程

  • 线程

    进程是一个运行的程序,线程则是程序不同的执行路径,比如qq包含聊天,浏览空间属于不同的线程

线程创建方式

  • Thread

    通过继承Thread类,重写run方法:
    MyThread myThread = new MyThread()
    myThread.start()

  • Runnable

    继承Runnable 接口
    MyThread{
    }

    new Thread(new MyThread).start()

    相比于继承Thread实现线程创建,通过继承方式有更好的扩展性

  • Callable

    实现Callable接口 重写call方法,call方法有返回值

    new Thread(new FutureTask<String>(new MyCallThread())).start()

线程状态

  • Ready
  • Running
  • Terminated
  • TimedWaiting
  • Waiting
  • Blocked

线程通信

  • Thread

    • wait() 会释放锁,必须在synchronized中使用
    • notify() 不释放锁,必须在synchronized中使用
  • LockSupport

    • park()
    • unpark(t)

volatile

  • 保证可见性

    在线程中,会拷贝变量的副本,修改操作基于副本进行,结束后讲修改结果写回原有变量,线程内的修改对其他线程不可见

    假设有A和B 两个线程和变量C,volitale 修饰C,A线程中对C的修改将会立马作用在变量C上

  • 禁止指令重排

    在程序编译的过程中,可能会对代码进行优化,虽然最终执行结果一样,但是执行顺序可能发生改变,在多线程环境中可能会出错。

  • double check 单例模式需不需要加volatile

    需要,如果不加,指令重排可能导致问题。

    public class DoubleCheck {
    private static volatile DoubleCheck INSTANCE;
    private DoubleCheck(){}

    public DoubleCheck getINSTANCE(){
        if(INSTANCE == null){
            synchronized (DoubleCheck.class){
                if(INSTANCE == null) 
                    INSTANCE =  new DoubleCheck();
            }
        }
        return INSTANCE;
    }
    

    }

synchronized

  • 同步锁

    • 锁方法
    • 锁代码块
    • 锁Object
  • 锁升级

    首先加偏向锁(在这个Object的头上面markword记录这个线程,即在第一个线程访问的时候实际上时没有给这个Object加锁的,在内部实现的售后,只是记录这个线程的ID(偏向锁)),
    如果有线程争用的话,就升级为自旋锁,
    自旋锁转10次之后,升级为重量锁,重量所就是去操作心痛哪里申请资源。

  • 重入性

    加锁方法可以调用其他加锁方法,

    如果两个方法存在嵌套调用关系,且持有同一把锁,则内层方法可以直接执行。

CAS

  • compare and swap

    cas(V,Expectded,NewValue){
    if V==E
    V = NEW
    otherwise try again or fail
    }

Atomic类和线程同步新机制

Atomic

  • AtomicInteger AtomicLong
  • LongAdder

新机制

  • ReentranLock

    ReentrantLock 可以替代synchronized是没问题的,也可以重入,是可以锁定的。本身的底层是cas

- lock()
- unlock()
  • CountDownLatch

    • 计数门闩
  • CylicBarrier

    • 循环栅栏
  • Phaser

    • 阶段

      更像是结合了CountDownLatch和CyclicBarrier,

线程池

容器

面试过程中如何聊容器类
可以从两大面开始聊,容器分为两大类Collection,Map,Collection又分为三大类:List Set Queue队列,队列即时一队一队的,往队列里取数据时它和这个List Set 都不一样。大家知道List取得时候如果Array的话还可以取到其中的一个。Set主要和其他的区别就是中间时唯一的,不会有重复元素。Queue实现了一个什么逻辑呢,实际上就是一个队列,队列什么概念,有进有出,那么再这个基础之上,它实现了许多的线程访问方法(比如put阻塞式的放,take阻塞式的取),这个式其他的list set里没有的,队列的最主要原因是为了实现任务的装在的种种取和装这里面最重要的就是叫做阻塞队列,它的实现初衷是为了线程池高并发做准备。

  • Collection

    • List

      • CopyOnWriteList
      • Vector
      • ArrayList
      • LinkedList
    • Set

      • HashSet

        • LinkedHashSet
      • SortedSet

        • TreeSet
      • EnumSet

      • CopyOnWriteArraySet

      • ConcurrentSkipListSet

    • Queue

      Queue和List的区别到底在哪里,主要就是Queue添加了offer peek poll put take这些个对线程友好的或者阻塞或者等待的方法。

    - Dequeue
    - BlockingQueue

        - ArrayBlockingQueue
        - PriorityBlockingQueue
        - LinkedBlockingQueue
        - TransferQueue
        - SynchronousQueue

    - PriorityQueue
    - DelayQueue
  • Map

    • HashMap

      • LinkedHashMap
    • TreeMap

    • WeakHashMap

    • IdentityHashMap

    • ConcurrrentHashMap

    • ConcurrentSkipListMap

阻塞队列

线程池

  • 线程池7大参数

    • 核心线程数

    • 最大线程数

    • 生存时间

    • 生存时间单位

    • 任务任务队列

    • 线程工厂

    • 拒绝策略

      • Abort

        抛异常

    - Discard

      扔掉 不抛异常
      

    - DiscardOldest

      扔掉排队时间最久的
      

    - CallerRuns

      调用者处理服务
      

    - 自定义拒绝策略
  • 原理

    • 分类

      • ThreadPoolExecutor

      • ForkJoinPool

        Fork分叉,分叉完再分叉,最后结果汇总叫join

- ThreadPoolExecutor实现

  Executor接口,接口把线程的定义和执行分开
  ExecutorService实现Executor接口,定义线程池的生命周期方法
  然后才是各种各样的ThreadPoolExecutor : 把线程池作为一个执行单元,给他单独出来一个类
  Executors 是工具类,生成各种线程池

XMind - Trial Version


https://www.xamrdz.com/backend/34r1994802.html

相关文章: