Kafka
Kafka入门
什么是Kafka
Kafka 是一个分布式的基于发布/订阅模式的消息队列(Message Queue),主要应用与大数据实时处理领域。
消息队列
Kafka 本质上是一个 MQ(Message Queue),使用消息队列的好处?
解耦:允许我们独立的扩展或修改队列两边的处理过程。
可恢复性:即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
缓冲:有助于解决生产消息和消费消息的处理速度不一致的情况。
灵活性&峰值处理能力:不会因为突发的超负荷的请求而完全崩溃,消息队列能够使关键组件顶住突发的访问压力。
异步通信:消息队列允许用户把消息放入队列但不立即处理它
概述 Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/nginx日志、访问日志,消息服务等等,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。
Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动 ...
ElasticSearch
ElasticSearch 概述
概述Elasticsearch 是什么
Elasticsearch(简称ES)是一个基于Apache Lucene(TM)的开源搜索引擎
Elasticsearch 是一个高伸缩的开源全文搜索和分析引擎,是一个基于JSON的分布式搜索和分析引擎,基于restful web接口,Elasticsearch是用Java语言开发的,基于Apache协议的开源项目,是目前最受欢迎的企业搜索引擎。
它可以快速地、近实时的存储,搜索和分析大规模的数据。一般被用作底层引擎/技术,为具有复杂搜索功能和要求的应用提供强有力的支撑。
ElasticSearch特点
Elasticsearch是实时的分布式搜索分析引擎,内部使用Lucene做索引与搜索,有以下特点
近实时性:新增到 ES 中的数据在1秒后就可以被检索到,这种新增数据对搜索的可见性称为“近实时搜索”
全文检索:将全文检索、数据分析以及分布式技术,合并在了一起,才形成了独一无二的ES
分布式:意味着可以动态调整集群规模,弹性扩容
集群规模:可以扩展到上百台服务器,处理PB级结构化或非结构化数据
开箱即 ...
NIO
NIO简单介绍前言Java NIO有两种解释:
一种叫非阻塞IO(Non-blocking I/O)
另一种叫新的IO(New I/O)
其实两种概念也是相同的。
一、概述Java NIO是从Java1.4版本开始引入的一个新的IO API,可以代替标准的IO API。
NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的,基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
NIO有三大核心部分
Channel(通道)
Buffer(缓冲区)
Selector(选择器)
二、Java NIO与BIO的区别
BIO以流的方式处理数据,而NIO以块的方式处理数据,块IO的效率比流IO高很多;
BIO是阻塞的,NIO则是非阻塞的;
BIO基于字节流和字符流进行操作,而NIO基于Channel(通道)和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择器)用于监听多个通道的事件(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道;
BIO是单向的,如:Input ...
java中AQS的方法结构
java中AQS的方法结构
AQS的方法结构 如果我们理解了上一节的设计思路,我们大致就能知道AQS的主要数据结构了。
组件
数据结构
同步状态
volatile int state
阻塞
LockSupport类
队列
Node节点
条件队列
ConditionObject
进而再来看下AQS的主要方法及其作用。
属性、方法
描述、作用
int getState()
获取当前同步状态
void setState(int newState)
设置当前同步状态
boolean compareAndSetState(int expect, int update)
通过CAS设置当前状态,此方法保证状态设置的原子性
boolean tryAcquire(int arg)
钩子方法,独占式获取同步状态,AQS没有具体实现,具体实现都在子类中,实现此方法需要查询当前同步状态并判断同步状态是否符合预期,然后再CAS设置同步状态
boolean tryRelease(int arg)
钩子方法,独占式释放同步状态,AQS没有具体实 ...
java中AQS的源代码实现
java中AQS的源代码实现
AQS的源代码实现主要通过独占式同步状态的获取和释放、共享式同步状态的获取和释放来看下AQS是如何实现的。
独占式同步状态的获取和释放独占式同步状态调用的方法是acquire,代码如下:
public final void acquire(long arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
上述代码主要完成了同步状态获取、节点构造、加入同步队列以及在同步队列中自旋等待的相关工作,其主要逻辑是:首先调用子类实现的tryAcquire方法,该方法保证线程安全的获取同步状态,如果同步状态获取失败,则构造独占式同步节点(同一时刻只能有一个线程成功获取同步状态)并通过addWaiter方法将该节点加入到同步队列的尾部,最后调用acquireQueued方法,使得该节点以自旋的方式获取同步状态。如果获取不到则阻塞节点中的线程,而被阻塞线程的唤醒主要依靠前 ...
java原子操作CAS
java原子操作CAS
无锁的概念 在谈论无锁概念时,总会关联起乐观派与悲观派,对于乐观派而言,他们认为事情总会往好的方向发展,总是认为坏的情况发生的概率特别小,可以无所顾忌地做事,但对于悲观派而已,他们总会认为发展事态如果不及时控制,以后就无法挽回了,即使无法挽回的局面几乎不可能发生。这两种派系映射到并发编程中就如同加锁与无锁的策略,即加锁是一种悲观策略,无锁是一种乐观策略,因为对于加锁的并发程序来说,它们总是认为每次访问共享资源时总会发生冲突,因此必须对每一次数据操作实施加锁策略。而无锁则总是假设对共享资源的访问没有冲突,线程可以不停执行,无需加锁,无需等待,一旦发现冲突,无锁策略则采用一种称为CAS的技术来保证线程执行的安全性,这项CAS技术就是无锁策略实现的关键,下面我们进一步了解CAS技术的奇妙之处。
什么是CAS
CAS(Compare and Swap),即比较并替换,是用于实现多线程同步的原子指令。
执行函数:CAS(V,E,N)
其包含3个参数
V表示要更新的变量
E表示预期值
N表示新值
假定有两个操作A和B,如果从执行A的线程来看,当另一个线程执行B时,要 ...
JAVA更多的锁问题
JAVA更多的锁问题
饥饿和公平 如果一个线程因为其他线程获取了所有的CPU时间而没有获取到CPU时间,被称为“饥饿”。线程被“饿死”,因为其他线程能够使用CPU而它不能。饥饿的解决方案被称为“公平” - 所有线程都被公平地授予执行机会。
发生饥饿的原因
以下三个常见原因可能导致Java中线程的饥饿
线程抢占
具有高优先级的线程会从优先级较低的线程中占有所有CPU时间。
您可以单独设置每个线程的线程优先级。优先级越高,给予线程的CPU时间越多。您可以将线程的优先级设置在1到10之间,具体交互方式取决于运行应用程序的操作系统(关于线程优先级前面已经提及)。对于大多数应用程序,您最好保持优先级不变。
线程阻塞
线程被无限期地阻塞,等待进入同步块,因为其他线程在它之前一直被允许进入同步块中。
Java的同步代码块可能是饥饿的另一个原因。Java的同步代码块不保证进入同步块的线程的顺序。这意味着存在一个理论上的风险,即线程在尝试进入块时永远被阻塞,因为其他线程在它之前一直被授予访问权限。这个问题被称为“饥饿”,一个线程被“饿死”,因为其他线程获取了CPU时间而不是它。
线程等待
在一 ...
ThreadLocal源码解析01
ThreadLocal源码解析01
先看下set的流程图
ThreadLocal 简介 ThreadLocal 在面试中经常提到,关于ThreadLocal使用不当造成OOM以及在特殊场景下,通过ThreadLocal可以轻松实现一些看起来复杂的功能,都说明值得花时间研究其原理。
ThreadLocal 不是 Thread,是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,每个线程存储的是主线程变量的副本,子线程操作的是对副本进行操作,不影响其他子线程的中的数据,所以一般说,ThreadLocal不保证线程的安全,只保证线程的隔离。
举个例子,如果ThreadLocal保存保存的是一个静态变量,副本都是静态变量自己,这样就又会出现线程安全问题。
ThreadLocal 注意事项
ThreadLocal类封装了getMap()、set()、get()、remove()4个核心方法
通过getMap()获取每个子线程Thread持有自己的ThreadLocalMap实例, 因此它们是不存在并发竞争的。可以理解为每个线程有自己的变量副本。
ThreadLocalMap中E ...
java中的AQS
java中的AQS
什么是AQS AQS是AbstractQueuedSynchronizer的简称。AQS提供了一种实现阻塞锁和一系列依赖FIFO等待队列的同步器的框架,如下图所示。AQS为一系列同步器依赖于一个单独的原子变量(state)的同步器提供了一个非常有用的基础。子类们必须定义改变state变量的protected方法,这些方法定义了state是如何被获取或释放的。鉴于此,本类中的其他方法执行所有的排队和阻塞机制。子类也可以维护其他的state变量,但是为了保证同步,必须原子地操作这些变量。
AbstractQueuedSynchronizer中对state的操作是原子的,且不能被继承。所有的同步机制的实现均依赖于对改变量的原子操作。为了实现不同的同步机制,我们需要创建一个非共有的(non-public internal)扩展了AQS类的内部辅助类来实现相应的同步逻辑。AbstractQueuedSynchronizer并不实现任何同步接口,它提供了一些可以被具体实现类直接调用的一些原子操作方法来重写相应的同步逻辑。AQS同时提供了互斥模式(exclusive)和共享模 ...
CLH队列锁的原理
CLH队列锁的原理
什么是CLH队列锁 CLH锁是有由Craig, Landin, and Hagersten这三个人发明的锁,取了三个人名字的首字母,所以叫 CLH Lock。
CLH锁是一个自旋锁。能确保无饥饿性。提供先来先服务的公平性。
CLH队列锁也是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程仅仅在本地变量上自旋,它不断轮询前驱的状态,假设发现前驱释放了锁就结束自旋。
就像这样
当一个线程需要获取锁时
创建一个的QNode,将其中的locked设置为true表示需要获取锁,myPred表示对其前驱结点的引用
线程A对tail域调用getAndSet方法,使自己成为队列的尾部,同时获取一个指向其前驱结点的引用myPred
线程B需要获得锁,同样的流程再来一遍
线程就在前驱结点的locked字段上旋转,直到前驱结点释放锁(前驱节点的锁值 locked == false)
当一个线程需要释放锁时,将当前结点的locked域设置为false,同时回收前驱结点
如上图所示,前驱结点释放锁,线程A的myPred所指向的前驱结点的locked字段变为fa ...
ThreadLocal引发的内存泄漏分析
ThreadLocal引发的内存泄漏分析
预备知识引用
Object o = new Object();
这个o,我们可以称之为对象引用,而new Object()我们可以称之为在内存中产生了一个对象实例。
当写下 o=null时,只是表示o不再指向堆中object的对象实例,不代表这个对象实例不存在了。
强引用: 就是指在程序代码之中普遍存在的,类似“Object obj=new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象实例。
软引用: 是用来描述一些还有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象实例列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK 1.2之后,提供了SoftReference类来实现软引用。
弱引用: 也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象实例只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象实例。在JDK 1.2之后,提供了WeakRe ...
ThreadLocal
什么是ThreadLocal**
什么是ThreadLocal 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。
所以,在Java中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没有在Java开发者中得到很好的普及。
与Synchonized的比较 ThreadLocal和Synchonized都用于解决多线程并发访问。可是ThreadLocal与synchronized有本质的差别。synchronized是利用锁的机制,使变量或代码块在某一时该仅仅能被一个线程访问。而ThreadLocal为每个线程都提供了变量的副本,使得每个线程在某一时间访问到的 ...