Java内存模型
Java内存模型并发编程模型的两个关键问题
线程之间如何通信(以何种机制来交换信息)
在命令式编程中,线程之间的通信机制有两种,共享内存和消息传递
Java并发采用的是共享内存模型 Java线程之间的通信总是隐式进行…
线程之间如何同步
同步是指程序中用于控制不同线程间操作发生相对顺序的机制.
在共享内存并发模型里,同步是显式进行的.程序员必须显式指定某个方法或某段代码需要在线程之间互斥执行.
在消息传递的并发模型里,由于消息的发送必须在消息的接收之前,因此同步是隐式进行的
Java内存模型的抽象结构在Java中,所有实例域,静态域和数组元素都存储在堆内存中,堆内存在线程之间共享.
局部变量和异常处理器参数不会在线程之间共享,因此他们不会有内存可见性问题,也不会受内存模型的影响.
这跟JVM堆栈的知识匹配上了
Java线程之间的通信由Java内存模型控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见
线程之间的共享变量储存在主内存中
每一个线程都有一个私有的本地内存
本地内存存储了该线程以读/写共享变量的副本**.本地内存是JMM的一个抽象概念,并不真实存在**. ...
Java中的锁
Java中的锁Lock接口锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(有些锁可以允许多个线程并发地访问共享资源,比如读写锁)
Java SE5之后,并发包中新增了Lock接口(以及其实现类)来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用的时候需要显示地获取锁和释放锁
虽然缺少了synchronized隐式获取锁的便捷性,但是却拥有了锁获取与释放的可操作性,可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步
123456Lock lock = new ReentranLock();lock.lock();try{}finally{ lock.unlock();}
不需要将获取锁的过程写在try中,因为如果在获取锁(自定义锁的实现)时发生了异常,异常抛出的同时.也会导致锁无故释放.
Lock接口提供的synchronized关键字所不具备的主要特性
尝试非阻塞地获取锁
当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则成功获取 ...
原子操作的实现原理
原子操作的实现原理原子(atomic)本意是”不能被进一步分割的最小粒子”,而原子操作(atomic operation)意为”不可被中断的一个或者一系列操作”
术语定义缓存行(Cache line);缓存的最小操作单位
比较并交换(Compare and swap)CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先比较旧值有没有变化,如果没有发生变化,才交换成新值,发生了变化则不交换
CPU流水线(CPU pipeline)CPU流水线的工作方式就像工业生产上的装配流水线,在CPU中由56个不同功能的电路单元组成一条指令处理流水线,然后将一条x86指令分成56步再由这些电路单元分别执行,这样就能实现在一个CPU时钟周期完成一条指令,因此提高CPU的运算速度
内存顺序冲突(Memory order violation)内存顺序冲突一般是由假共享引起的,假共享是指多个CPU同时修改同一个缓存行的不同部分而引起其中一个CPU的操作无效,当出现这个内存顺序冲突时,CPU必须清空流水线
处理器如何实现原子操作使用总线锁保证原子性所谓总线锁就是使用处理器提供的一个LO ...
RabbitMQ工作模式
RabbitMQ工作模式官网对应模式介绍:https://www.rabbitmq.com/getstarted.html
1. Work queues工作队列模式1.1 模式说明
Work Queues与入门程序的简单模式相比,多了一个或一些消费端,多个消费端共同消费同一个队列中的消息。
应用场景:对于 任务过重或任务较多情况使用工作队列可以提高任务处理的速度。
1.2 代码Work Queues与入门程序的简单模式的代码是几乎一样的;可以完全复制,并复制多一个消费者进行多个消费者同时消费消息的测试。
生产者12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667package com.itheima.producer;import com.rabbitmq.client.Channel;import com.rabbitmq.client.Connection;import com.rab ...
什么是CAS?
什么是CAS?CompareAndSwapInt
CAS乐观锁:多个线程使用CAS同时更新同一个变量时,只有一个线程更新变量的值其他线程被告知失败,可以再次尝试
CAS有可能带来ABA问题(1->8->1)如果在乎:
AtomicStampedReference
每次改变都需要版本号
AtomicMarkableReference
不在乎改了多少次,只在乎改没改
如果在写回去的时候被打断了,怎么办?
写回去的时候必须保障原子性(硬件底层保证原子性)
并发编程3大特性 可见性 原子性 有序性
ElasticSearch安装和基础
ElasticSearch开源的ElasticSearch是目前全文搜索引擎的首选,可以快速的存储,搜索和分析海量数据
近乎实时存储检索 可以处理pb级别的数据 es使用java开发 和lucene作为核心
目的通过简单的Restful API来隐藏 Lucene的复杂性 从而让全文搜索变简单
去年的虚拟机上的es居然还可以正常启动
Docker安装
下载镜像文件
12docker pull elasticsearch:7.4.2docker pull kibana:7.4.2
创建实例
1234567891011121314151617181920212223242526272829303132333435# 给虚拟机创建自己的目录 为了后面把配置挂载出来mkdir -p /mydata/elasticsearch/configmkdir -p /mydata/elasticsearch/data# 表示es可以用远程的任何机器访问echo "http.host:0.0.0.0">>/mydata/elasticsearch/config/ela ...
线程池
线程池基本概念什么是线程池?线程池其实就是一种多线程处理的方式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务.这里的线程就是我们前面学过的线程,这里的任务就是我们前面学过了的实现了Runnable或Callable接口的实例对象;
为什么使用线程池?使用线程池最大的原因就是可以根据系统的需求和硬件环境灵活的控制线程的数量,且可以对线程进行统一的管理和控制,从而提高系统的运行效率,降低系统运行压力.
使用线程池有什么优势?
线程和任务分离,提高线程重用性
控制线程并发数量,降低服务器压力,统一管理所有线程
提升系统响应速度,假如创建线程用的时间是T1,执行任务的时间是T2,摧毁线程的时间T3, 那么使用线程池就免去T1和T3的时间;
工作原理ThreadPoolExecutor
1234567public ThreadPoolExecutor(int corePoolSize, //核心线程数量 int maximumPoolSize, //最大线程数 long ...
多线程
多线程线程可以有如下6种状态:
New (新建)
Runnable (可运行)
Blocked (阻塞)
Waiting (等待)
Timed waiting (计时等待)
Terminated (终止)
要获得一个线程的状态,只需要调用getState方法
新建线程当使用new操作符创建一个新线程时,如new Thread(r),这个线程还没有开始运行.
这意味着它的状态是新建(new).
可运行线程一旦调用start方法,线程就处于可运行状态(Runnable)
一个可运行的线程可能正在运行也可能没有运行
阻塞和等待线程当线程处于阻塞或者等待状态时,它暂时是不运动的.它不运行任何代码,而且消耗最少的资源. 要由线程调度器重新激活这个线程
当一个线程视图获取一个内部的对象锁.而这个锁目前被其他线程占用,该线程就会被阻塞. 当所有的线程都释放了这个锁,并且线程调度器允许该线程持有这个锁时,他将变成非阻塞状态.
当线程等待另一个线程通知调度器出现一个条件时,这个线程会进入等待状态. 调用Object.wait方法或者Thread.join方法,或者等待Java.util.concur ...
Synchronized的实现原理和应用
Synchronized的实现原理和应用很多人称呼它为重量级锁.但是随着Java SE1.6对Synchronized进行优化后,有些情况下就没有那么重了.
Java的每一对象都可以作为锁具体的实现方式:
对于普通的同步方法,锁是当前的实例对象
对于静态同步方法,锁是当前类的Class对象
对于同步方法块,锁是Synchronized括号里配置的对象
Java对象头Synchronized的用的锁是存在Java对象头里面的.如果对象是数组类型,则虚拟机用三个字宽(Word)存储对象头.
如果是非数组,则是2字宽存储对象头
在32位虚拟机中,1字宽等于4字节,即32bit,如下图
Java 对象头的长度
长度
内容
说明
32/64bit
Mark Word
存储对象的hashCode或锁信息
32/64bit
Class Metadata Address
存储到对象类型数据的指针
32/32bit
Array length
数组的长度(如果当前对象是数组)
Java对象头里的Mark Word里默认存储对象的Hash Code,分代年龄和锁标记位
Java对 ...
Java并发编程的艺术
Java并发编程的艺术(读书笔记)第一章 并发编程的挑战(0312)
即使是单核处理器也支持多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制,CPU不断地切换线程执行
上下文切换: 任务从上一个保存到再次加载这个任务的过程就是一次上下文切换
并发不一定比串行快,因为线程有创建和上下文切换的开销
Lmbench3可以测量上下文切换的时长
vmstat可以测量上下文切换的次数
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647public class ConcurrentTest { //实测只有上亿次 并发才会比串行快 private static final Long count=100000000L; public static void main(String[] args) throws InterruptedException { concurrency(); seri ...