K8s概述(前言)

卤煮之前在某厂商做toB项目的时候,需要去客户那里做私有化部署。一开始用的手工部署,多机部署要维护互联关系,还有各种词典、健康检查等都需要自己手动做,模块多起来之后简直就是灾难。后面上了整套k8s部署,大大的解放了生产力,把问题转移到了如何更好的使用k8s上面。 这里我对比一下跟物理机部署比起来,为什么我们要用k8s做私有化部署: 物理机、虚拟机部署 k8s容器化部署 创建一个AWS实例、或一台可用物理机 起一个容器 Puppet/ansible指明安装部署的二进制文件、 ...

Spring sidecar模式纳入TF-Serving(一):sidecar模式实验

前言 因为客服在线模块在线上要使用到tf-serving做在线推理,所以需要把C++模块集成进来。这一篇主要讲sidecar的实验部分,会起一个Django进程嵌入SpringCloud中做非JVM微服务来做实验。 起Eureka 在 https://start.spring.io/ 勾选Eureka Server Application加上EnableEurekaServer: @SpringBootApplication @EnableEurekaServer public class CloudApplication ...

LongAdder

LongAdder是jdk8新增的用于高并发环境的计数器。 Atomicxxx使用硬件级别的指令CAS来更新计数器的值,在高并发的情况下每次只能有一个线程能成功,竞争失败的线程会非常多,白白浪费了很多cpu事件,因为竞争失败的线程会自旋。 jdk8的AtomicLong: // jdk1.8的AtomicLong的实现代码,这段代码在sun.misc.Unsafe中 // 当线程竞争很激烈时,while判断条件中的CAS会连续多次返回false,这样就会造成无用的循环,循环中读取volatile变量的开销本来就是比较高的 // 因为这样,在高并发时,AtomicXXX并不是那么理想的计数方式 public ...

Java并发类库提供的线程池有哪几种? 分别有什么特点? - 《Java核心》笔记

通常都是使用Executors提供的通用线程池创建方法去创建不同配置的线程池,主要区别在于不同的ExecutorService类型或者不同的初始参数,主要分为五类: newCachedThreadPool() 用于处理大量短时间工作任务的线程池。会试图缓存线程并重用,当无缓存线程可用时,会创建新的工作线程。如果线程闲置时间超过60秒,则被终止并移出缓存。长时间闲置时,这种线程池不会消耗什么资源。其内部使用SynchronousQueue作为工作队列。 newFixedThreadpool(int nThreads) 重用固定数目的线程,背后使用的是无界的工作队列。如果任务数量超过了nThread,将在工作队列中等待空闲线程出现。 ...

AQS(转)

简介 AQS:AbstractQueuedSynchronizer,队列同步器,Java中同步组件的基础框架。JUC并发包中的核心基础组件。 AQS解决了子类实现同步器时涉及到的大量细节问题,例如获取同步状态、FIFO同步队列。 基于AQS构建的同步器中,只能在一个时刻发生阻塞,从而降低上下文切换的开销,提高了吞吐量。 AQS的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态。 AQS使用一个int类型的成员变量state来表示同步状态,当state>0时表示已经获取了锁,当state ...

LockSupport源码分析

concurrent包基于AQS框架,AQS框架基于两个类: Unsafe(提供CAS操作) LockSupport(提供park/unpark操作) 概念 LockSupport public static void park() { UNSAFE.park(false, 0L); } public static void ...

条件变量pthread_cond_t

条件变量是什么 条件变量是线程同步的一种手段,用于阻塞线程直到条件发生。 条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个/多个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"信号。 代码示例: #include <pthread. ...

并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别? - 《Java 核心技术》笔记

Concurrent* 容器,基于lock-free,在常见的多线程访问场景,一般可以提供较高吞吐量; LinkedBlockingQueue内部基于锁,并提供了BlockingQueue的等待性方法。 Concurrent* 性质 java.util.concurrent包提供的容器(Queue、List、Set)、Map从命名上可以大概分为Concurrent* 、CopyOnWrite和Blocking等三类: Concurrent没有类似CopyOnWrite之类容器相对较重的修改开销; Concurrent提供了较低的遍历一致性。比如当利用迭代器遍历时, ...

Java并发包提供的并发工具类 - 《java核心》笔记

提供了各种丰富的同步结构,包括CountDownLatch、CyclicBarrier、Semaphore等,可以实现更加丰富的多线程操作,比如利用Semaphore作为资源控制器,限制同时进行工作的线程数量; 各种线程安全的容器,比如ConcurrentHashMap,有序的ConcurrentSkipListMap,通过类似快照机制实现线程安全的动态数组CopyOnWriteArrayList; 各种并发队列实现,比如BlockedQueue,ArrayBlockingQueue、SynchorousQueue,或针对特定场景的PriorityBlockingQueue等; 强大的Executor,可以创建各种不同类型的线程池,调度任务运行等。 问题 ...

死锁 - 《Java 核心》笔记

定位死锁常见方式 必定会出现死锁的程序: public class DeadLockSample extends Thread { private String first; private String second; public DeadLockSample(String name, String first, String ...

ConcurrentSkipListMap实现原理

跳表介绍 跳表是一种随机层次的数据结构,通过建立多级索引,实现以二分查找遍历一个有序链表。 SkipList让已排序的数据分布在多层链表中,以0~1随机数决定一个数据的向上攀升与否,以时间换空间的一个算法。 SkipList的性质: 多层结构,level通过一定概率随机产生; 每一层都是一个有序链表; 最底层包含所有元素; 如果一个元素出现在第i层,则i层以下也包含这个元素; 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。 性能对比 ConcurrentHashMap和ConcurrentSkipListMap对比, ...

Phaser

Phaser是JDK1.7引入的一个同步工具类,适用于一些需要分阶段的任务处理。一种人物可以分为多个阶段,现希望保证只有前面一个阶段的任务完成后才能开始后面的任务。这种场景可以使用多个CyclicBarrier来实现,但是需要明确知道总共有多少个阶段,且无法动态修改。Phaser可以同时解决这两个问题。 同步器 作用 CountDownLatch 倒数计时器 CyclicBarrier 循环栅栏,初始时设定参与线程数,当线程到达栅栏后,会等待其他线程的到达。当到达栅栏的总数满足指定数后,所有等待的线程继续执行。 ...

ForkJoinPool

ForkJoinPool的作用 ThreadPoolExecutor每个任务都是单独线程处理的。如果某个任务耗时很大,就可能出现其他线程都在等着这个线程结束的情况。 为了处理这种问题,ForkJoinPool将一个大任务拆分为多个小任务,使用fork可以将小任务分发给其他线程同时处理,使用join可以将多个线程处理的结果进行汇总。 ForkJoinPool的原理 ForkJoinPool中每个线程都有自己的双端列表用于存储任务。这个双端列表对于工作窃取算法非常重要。 public class ForkJoinWorkerThread extends Thread { final ForkJoinPool pool; // 工作线程所在的线程池 ...

协程

why 协程 协程的两大特点: 占用的资源更少; 所有的切换和调度都发生在用户态。 协程是一种轻量级、用户态的执行单元。拥有自己的寄存器上下文和栈。协程调度切换时,把寄存器上下文和栈保存到其他地方。在切回来的时候再恢复回来。 线程:抢占式多任务。 协程:协作式多任务。 不管是进程还是线程,阻塞、切换调度的时候都需要陷入系统调用,由CPU跑调度程序,再由调度程序决定跑哪一个进程( ...

Java Instrument

作用 Java Instrument指的是可以用独立于应用程序之外的代理程序来监测和协助运行在JVM上的应用程序,包括但不限于获取JVM运行时状态,替换和修改类定义。 使用方法 Java SE5及以后的版本,可以在一个普通Java程序运行时,通过-javaagent参数制定一个特定的jar文件(包含Instrumentation代理)来启动Instrumentation的代理程序。 代理类必须提供一个public static void premain(String args, Instrumentation inst) ...

一个线程两次调用start()方法会出现什么情况? - 《java核心技术》笔记

java的线程不允许启动两次,第二次调用会抛出IllegalThreadStateException,是一种运行时异常。 线程间状态流转: 就绪:该线程已经在JVM,可能正在运行,也可能正在等待系统分配给它CPU时间片,在就绪队列中排队; 阻塞:等待monitor lock; 等待:正在等待其他线程采取某些操作,比如消费者模式。 需要注意的一些点: 守护线程必须在线程启动之前设置 Thread daemonThread = new ...

java多线程(5) - Java虚拟机中的锁优化技术以及几种锁的介绍

线程的五种状态: 自旋锁 在程序中,Java虚拟机的开发工程师们在分析过大量数据后发现,共享数据的锁定状态一般只会持续很短的一段时间,为了这段时间去挂起和恢复线程其实并不值得。 如果物理机上有多个处理器,可以让多个线程同时执行的话,就可以让后来的线程“稍微(忙)等一下”,不会放弃处理器事件,看看持有锁的线程会不会很快释放锁。这个“稍微等一下”的过程就是自旋。 锁消除 在动态编译同步块的时候,JIT编译器可以借助一种叫逃逸分析( ...

java多线程(4) - Moniter的实现原理

Moniter是什么 我们可以把监视器理解为包含一个特殊的房间的建筑物,这个特殊房间同一时刻只能有一个客人。如果一个顾客想要进去这个房间,就需要在走廊(Entry Set)排队,调度器将基于某个标准来选择排队的客户进入房间。如果用户暂时因为其他事情无法脱身,那么就会被送到等待室(Wait Set)。 监视器是一个用来监视这些线程进入特殊的房间的,它的义务是保证(同一时刻)只有一个线程可以访问被保护的数据和代码。 Monitor其实是一种同步机制,通常被描述为一个对象,其主要特点是: ...

java多线程(3) - java的对象头

回顾 当一个Java类在被JVM加载后,JVM会给这个类创建一个instanceKlass,保存在方法区,用于在JVM层表示该Java类。 当我们在代码中new一个对象时,JVM会创建一个instanceOopDesc对象,包含了对象头以及实例数据。 对象头包括: class oopDesc { friend class VMStructs; private: volatile markOop _mark; union _metadata ...

java多线程(2) - Java的对象模型

java对象保存在堆内存中。在内存中,一个Java对象包含三部分:对象头、实例数据和对象填充。 对象头中包含锁状态标志、线程持有的锁等标志。 Java的对象模型 在JVM的内存结构中,对象保存在堆内存中。我们在对对象进行操作时,操作的是对象的引用。 那么对象本身在JVM中的结构是什么样的? oop-klass model HotSpot JVM的设计者不想让每个对象中都含有一个vtable(虚函数表)(HotSpot基于C++实现) ...

管程

作用 管程保证了同一时间只能有一个进程在管程内活动,使用condition变量让进入管程而无法继续执行的进程阻塞自己。 例子 先来看一段有问题的代码: #define TRUE 1 #define MAX 100 void insert_item(int); int remove_item(); int count ...

synchronized和ReentrantLock有什么区别呢? - 《java核心技术》笔记

ReentrantLock能够实现很多synchronized无法做到的细节控制,比如公平性fairness,或者利用定义条件等。 知识点扩展: 线程安全 线程安全的定义 保证多线程环境下共享的、可修改的状态的正确性。 进而推导出保证线程安全的两个方法: 封装:将对象内部状态隐藏、保护起来。 不可变。 线程安全需要的几个基本特性 原子性:相关操作不会中途被其他线程干扰,一般通过同步机制实现; 可见性:一个线程修改了某个共享变量,其状态能理解被其他线程知晓。 ...

谈谈你知道的设计模式? - 《java核心技术》笔记

分类 按照模式的应用目标大致分类: 创建型模式:是对对象创建过程的问题和解决方案的总结,比如单例、工厂、构建器、原型。 结构型模式:针对软件设计结构的总结,关注于类、对象继承、组合方式的实践经验,比如适配器、装饰者、桥接、代理、组合、外观、享元。 ...

谈谈接口和抽象类有什么区别? - 《java核心技术》笔记

回答 接口是行为的抽象,是抽象方法的集合,目的是API定义和实现分离。不包含任何非常量成员以及非静态方法;java8后增加了default method,java9后可以定义private defult method。比如java8中的Collection增加了一系列关于Lambda、Stream的default method。 抽象类是不能被实例化的类,主要目的是代码重用。 S.O.L.I.D原则 ...

Java有几种文件拷贝方式?哪一种最高效? - 《java核心技术》笔记

java的几种文件拷贝方式?哪一种最高效? java.io的FileInputStream/FileOutputStream或者java.nio的transferTo/transferFrom。 nio方式可能更快,因为使用了零拷贝技术,数据传输不需要切换到用户态参与,减少了上下文切换和不必要的内存拷贝。 比如应用读取数据时,先在内核态将数据从磁盘读取到内核缓存,再切换到用户态将数据从内核缓存读取到用户缓存。 而NIO transferTo则直接在内核中进行数据拷贝。 提高类似拷贝等IO操作的性能的原则 使用缓存,减少IO次数; 使用transferTo等机制, ...

Java提供了哪些IO方式? NIO如何实现多路复用? - 《java核心技术》笔记

简述 同步阻塞IO库:传统的java.io包下面一些熟知的IO功能,比如File抽象,输入输出流等,交互方式是同步阻塞。java.net下面提供的部分网络API,比如Socket、ServerSocket、HttpURLConnection; 1.4引入的NIO,提供了Channel、Selector、Buffer等新的抽象,可以用于构建多路复用的、同步非阻塞IO,同时提供了更接近OS底层的高性能数据操作方式; ...

如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全? - 《java核心技术》笔记

简述 问:为什么需要ConcurrentHashMap? 答:因为Hashtable本身比较低效,它在所有的put、get、size方法上面加上了“synchronized”。而Collections提供的同步包装器,只是将“this”作为互斥的mutex。 早期的ConcurrentHashMap基于: 分段锁,将内部进行分段(Segment),里面是HashEntry的数组; HashEntry内部使用volatile的value字段保证可见性,也利用了不可变对象的机制以改进利用Unsafe提供的底层能力, ...