剪夏罗根,Lock锁子类了然一下

来源:http://www.caiyi100.cn 作者:澳门新葡京 人气:94 发布时间:2019-07-06
摘要:【出处】《浙江天目山药植志》 [" [" 【拼音名】Jiǎn Xià Luó Gēn n 前言n n n 回顾前面:n n n n多线程nn三分钟就可以入个门了!n n Threadn n源码nn剖析n n 多n n线程nn基础必要知识点!看了学

【出处】《浙江天目山药植志》

["

["

【拼音名】Jiǎn Xià Luó Gēn

n 前言n

n

n 回顾前面:n

n

  • n n 多线程nn 三分钟就可以入个门了!n
  • n Threadn n 源码nn 剖析n
  • n 多n n 线程nn 基础必要知识点!看了学习多线程事半功倍n
  • n Javan n 锁nn 机制了解一下n
  • n AQS简简单单过一遍n

n

n 只有光头才能变强!n

n

n 上一篇已经将Lock锁的基础AQS简单地过了一遍了,因此本篇主要是讲解Lock锁主要的两个子类:n

n

  • n ReentrantLockn
  • n ReentrantReadWriteLockn

n

n 那么接下来我们就开始吧~n

n

n 【编者的话】通过Minikube向Javan n 开发nn 人员n n Kubernetesnn 的相关操作n

【来源】为石竹科植物剪夏罗的根茎及根。夏秋采收,洗净晒干。

n 一、ReentrantLock锁n

n

n 首先我们来看看ReentrantLock锁的n n 顶部n n 注释nn n ,来看看他的相关特性呗:n

n

n 图片 1n

n

n 来n n 总结nn 一下要点吧:n

n

  • n 比n n synchronizednn 更有伸缩性(灵活)n
  • n 支持公平锁(是相对公平的)n
  • n 使用时最标准用法是在try之前调用lock方法,在n n finalnn lyn n 代码nn 块释放锁n

n

class X {n    private final ReentrantLock lock = new ReentrantLock();n    // ...nn    public void m() { n        lock.lock();  // block until condition holdsn        try {n            // ... method bodyn        } finally {n            lock.unlock()n        }n    }n}

n

n

【功能主治】治关节不利,腹泻,蛇缠。

n 1.1内部类n

n

n 首先我们可以看到有三个内部类:n

n

n 图片 2n

n

n 这些内部类都是AQS的子类,这就印证了我们之前所说的:n n AQS是ReentrantLock的基础,AQS是构建锁、n n 同步nn 器的框架n n

n

  • n 可以很清晰的看到,我们的ReentrantLock锁是支持公平锁和非公平锁的~n

n

n 图片 3n

n

n 我们n n 希望nn n 微服务nn 是可复制的,可替换的工作节点,这样可以轻松进行升级或降级,同时无需任何停机n n 时间nn ,并花费最少代价的n n 管理nn 。我们可以说我们希望他们成为我们的小黄人(minions)。本文我们将通过一个简单的例子来了解Kubernetes可以通过创建和编排一群“小黄人"来为我们做些什么。您可以与本文一起编码或从 此处 克隆项目。n

【用法用量】内服:煎汤,0.5~1两。外用:研末,柏子油调涂。

n 1.2n n 构造方法nn

n

n 图片 4n

n

n

【摘录】《*辞典》

n 1.3非公平lock方法n

n

n 尝试获取锁,获取失败的话就调用AQS的n n acquire(1)nn 方法n

n

n 图片 5n

n

n n acquire(1)nn 方法我们在AQS时简单看过,其中n n tryAcquire()nn 是子类来实现的n

n

n 图片 6n

n

n 我们去看看n n tryAcquire()nn :n

n

n 图片 7n

n

n 先决条件n

n

n 需要将使用n n Dockernn 容器化微服务以在Kubernetes中运行它们。我们将使用Minikube,而不是使用n n 云nn 托管的Kubernetes,以便可以在本地沙箱运行。n

n

n 1.4公平lock方法n

n

n 公平的lock方法其实就n n 多了一个状态条件n n :n

n

n 图片 8n

n

n 这个方法主要是判断 当前线程是否位于CLH同步队列中的第一个。如果是则返回flase,否则返回true 。n

n

n 图片 9n

n

n 目的n

n

n 我们的小黄人军团将是Java微服务。我们希望军团中有不同类型的工作角色,以便能够了解Kubernetes可以为我们做些什么。因此,我们的目标是让每个微服务都响应一个简单的n n httpnn 请求,其响应如下:n

n

n 图片 10n

n

n 使用ASCII字来表示minion的类型。n

n

n 1.5unlock方法n

n

n 图片 11n

n

n unlock方法也是在AQS中定义的:n

n

n 图片 12n

n

n 去看看n n tryRelease(arg)nn 是怎么实现的:n

n

n 图片 13n

n

n 构建Java Minion服务n

n

n 我们可以通过n n Spring Bootnn Web应用程序来启动我们的微服务,程序使用具有Web启动依赖性的 Spring Initializr 初始化:n

n

n 图片 14n

n

n 在项目中,创建一个使用@RestControllern n 注释nn 的Controller来处理请求。使用@RequestMapping(method = GET)来提供响应主体。所以首先我们可以这样做:n

n

n “`n

n

n @RequestMapping(method = GET)n

n

n @ResponseBodyn

n

n public String minion()throwUnknownHostException {n

n

n StringBuilder stringBuilder = new StringBuilder();n

n

n stringBuilder.append(“Host:”)。append(InetAddress.getLocalHost()。getHostName())。append(“<br/>”);n

n

n return stringBuilder.toString();n

n

n }n

n

n “`n

n

n 但这并不能完全满足n n 需求nn 。我们可以输出ASCII字,但选择哪种minion类型?为此可以使用一个技巧。创建一个可以采用我们选择的任何minion类型的应用程序。要做到这一点,我们需要它包含一个ASCII艺术字库。因此,我们创建了一个名为MinionsLibrary的类,使用@Component注解,在内部我们创建了一个地图,我们使用 此n n 博客nn 中的一些minions初始化:n

n

n “`n

n

n @Componentn

n

n public class MinionsLibrary {n

n

n private Map<String,String>n n mapnn = newn n HashMapnn <>();n

n

n public MinionsLibrary(){n

n

n map.put("one-eyed-minion",<COPY-PASTE MIn n NIOnn N ASCII ART HERE>);n

n

n map.put("two-eyed-minion",<COPY-PASTE MINn n IOnn N ASCII ART HERE>);n

n

n map.put("sad-minion",<COPY-PASTE MINION ASCII ART HERE>);n

n

n map.put("happy-minion",<COPY-PASTE MINION ASCII ART HERE>);n

n

n }n

n

n }n

n

n “`n

n

n 或者你可以从n n httpsnn ://n n gitnn hub.com/ryandawsonu … /demo 获取。n

n

n 然后告诉微服务是哪种minion类型。使用n n springnn 应用程序的名称属性(我们稍后可以使用docker环境变量设置)来执行此操作。它还将帮助我们稍后在响应中显示我们的应用程序版本,所以现在的Controller变为:n

n

n “`n

n

n @RestControllern

n

n public class Controller {n

n

n privaten n finalnn String version = "0.1";n

n

n private MinionsLibrary minionsLibrary;n

n

n @Value("${spring.applin n catnn ion.name}")n

n

n private String appName;n

n

n public Controller(MinionsLibrary minionsLibrary){n

n

n this.minionsLibrary=minionsLibrary;n

n

n }n

n

n @RequestMapping( method=GET)n

n

n @ResponseBodyn

n

n public String minion() throws UnknownHostException {n

n

n StringBuilder stringBuilder = new StringBuilder();n

n

n stringBuilder.append("Host: ").append(InetAddress.getLocalHost().getHostName()).append("<br/>");n

n

n stringBuilder.append("Minion Type: ").append(appName).append("<br/>");n

n

n stringBuilder.append("IP: ").append(InetAddress.getLocalHost().getHostAddress()).append("<br/>");n

n

n stringBuilder.append("Version: ").append(version).append("<br/>");n

n

n stringBuilder.append(minionsLibrary.getMinion(appName));n

n

n return stringBuilder.toString();n

n

n }n

n

n }n

n

n “`n

n

n 现在选择’image’包以匹配应用程序名称,该名称将是minion类型名称(例如’单眼小黄人’)。n

n

n 二、ReentrantReadWriteLockn

n

n 我们知道synchronized内置锁和ReentrantLock都是n n 互斥锁n n (一次只能有一个线程进入到临界区(被锁定的区域))n

n

n 而ReentrantReadWriteLock是一个n n 读写锁n n :n

n

  • n 在n n 读n n 取n n 数据nn 的时候,可以n n 多个线程同时进入到到临界区n n (被锁定的区域)n
  • n 在n n 写n n 数据的时候,无论是读线程还是写线程都是n n 互斥n n 的n

n

n 一般来说:我们大多数都是读取数据得多,修改数据得少。所以这个读写锁在这种场景下就很有用了!n

n

n 读写锁有一个接口ReadWriteLock,定义的方法就两个:n

n

n 图片 15n

n

n 我们还是来看看顶部注释说得啥吧:n

n

n 图片 16n

n

n 其实大概也是说明了:n n 在读的时候可以共享,在写的时候是互斥的n n

n

n 接下来我们还是来看看对应的实现类吧:n

n

n 图片 17n

n

n 按照惯例也简单看看它的顶部注释:n

n

n 图片 18n

n

n 于是我们可以总结出读写锁的一些要点了:n

n

  • n 读锁不支持条件对象,写锁支持条件对象n
  • n 读锁不能升级为写锁,写锁可以降级为读锁n
  • n 读写锁也有公平和非公平模式n
  • n n 读锁支持多个读线程进入临界区,写锁是互斥的n n

n

n 容器化并部署n

n

n 需要为我们的应用程序创建一个Docker镜像。我们想在Docker镜像中构建可执行的jar,然后在容器启动时启动Java应用程序。可以使用多阶段Docker构建来完成此任务。n n Dockerfilenn 是:n

n

n “`n

n

n FROMn n mavennn :3.5-jdk-8 as Bn n UInn LDMINIONn

n

n COPYn n srcnn /usr/src/myapp/srcn

n

n COPYn n pomnn .xml /usr/src/myappn

n

n RUN mvn -f /usr/src/myapp/pom.xml clean package -Dskn n ipnn Testsn

n

n FROM openjdk:alpinen

n

n COPY –from=BUILDMINION /usr/src/myapp/n n tarnn get/*.jar /maven/n

n

n CMDn n javann $JAVA_OPTS -jar maven/*.jarn

n

n “`n

n

n 从开始到’FROM openjdk:alpine’是构建JAR,然后jar包被拷贝到基于 轻量的openjdk:alpine镜像的下一阶段构建。n

n

n 使用JAVA_OPTSn n 参数nn 来限制程序的内存占用(关于降低内存,可以参考 该n n 文章nn )n

n

n 然后使用命令“dockern n buildnn . -t minion”构建一个镜像。n

n

n 通过创建Kubernetes部署文件来部署它。我们称之为“minion-army.yml”。这将包含每个minion类型的条目。这是其中的一个minion类型:n

n

n “`n

n

n apiVersion: apps/v1beta1n

n

n kind: Deploymentn

n

n metadata:n

n

n name: one-eyed-minionn

n

n labels:n

n

n serviceType: one-eyed-minionn

n

n spec:n

n

n replicas: 2n

n

n template:n

n

n metadata:n

n

n name: one-eyed-minionn

n

n labels:n

n

n serviceType: one-eyed-minionn

n

n spec:n

n

n containers:n

n

n - name: one-eyed-minionn

n

n image: minion:latestn

n

n imagePullPolicy: Nevern

n

n ports:n

n

n - containerPort: 8080n

n

n env:n

n

n - name: JAVA_OPTSn

n

n n valuenn : -Xmx64m -Xms64mn

n

n - name: SPRING_APPLICATION_NAMEn

n

n value: "one-eyed-minion"n

n

n —n

n

n apiVersion: v1n

n

n kind:n n Servicenn

n

n metadata:n

n

n name: one-eyed-minion-entrypointn

n

n namespace: defaultn

n

n spec:n

n

n selector:n

n

n serviceType: one-eyed-minionn

n

n ports:n

n

  • n

    n port: 8080n

    n

    n targetPort: 8080n

    n

    n n nodenn Port: 30080n

    n

n

n type: NodePortn

n

n “`n

n

n 请注意,“SPRING_APPLICATION_NAME”变量会自动与spring.application.name属性匹配,以便此minion服务成为单眼小黄人类型。有两个这种minion类型的n n 实例nn (副本)可用,Kubernetes服务将自动将请求路由到其中一个或另一个。n

n

n 该服务将面向Kubernetes以外的世界 – 与Minikube一起请求30080n n 端口nn 将进入该服务。 (对于真正的Kubernetes,服务的这一点会有所不同,因为我们使用LoadBalancer而不是NodePort,并且不会限制在minikube端口范围。)服务将使用与服务匹配的Pod来处理它。我们将为每种类型提供一种服务。n

n

n minion类型的部署将创建两个Pod。每个人都是这种类型的奴才。n

n

n 我们可以为每个minion类型重复上面的n n 配置nn ,每次增加外部端口号以便使用不同的端口。或者我们可以使用这个Github存储库,它还具有其他配置,可以在不停机的情况下进行小型版本升级。 (如果我们使用helm,我们可以避免重复,但我们不想添加比我们更多的工具。)n

n

n 2.1ReentrantReadWriteLock内部类n

n

n ReentrantReadWriteLock比ReentrantLock锁n n 多了两个内部类(都是Lock实现)来维护读锁和写锁n n ,但是n n 主体还是使用Synn n :n

n

  • n WriteLockn
  • n ReadLockn

n

n 图片 19n

n

n 创建军团n

n

n 首先启动mMinikube:n

n

n minikube start –memory 4000 –cpus 3n

n

n 等待它开始,然后将您的Docker registry 链接到Minikube,并为Minikube构建minion图像:n

n

n “`n

n

n eval $(minikube docker-env)n

n

n docker build . -t minionn

n

n “`n

n

n 然后我们可以部署军团:n

n

n n kubectl create -f minion-army.ymlnn
n

n

n 并看到类型:n

n

n “`n

n

n open ip):30080n

n

n open ip):30081n

n

n open ip):30082n

n

n open ip):30083n

n

n “`n

n

n 每个看起来都很像文章开头的快乐小黄人页面。n

n

n 我们可以通过“kubectl get pods”来查看整个军队,或者“minikube dashboard”进到n n Podsnn 页面n

n

n 图片 20n

n

n 2.2读锁和写锁的状态表示n

n

n 在ReentrantLock锁上使用的是state来表示同步状态(也可以表示重入的次数),而在ReentrantReadWriteLock是这样代表读写状态的:n

n

n 图片 21n

n

n 创造更多的部队n

n

n 我们可以在minikube dashboard的Deployments部分下创建更多特定类型的minions:n

n

n 图片 22n

n

n 2.3写锁的获取n

n

n 主要还是调用syn的n n acquire(1)nn :n

n

n 图片 23n

n

n 进去看看实现:n

n

n 图片 24n

n

n 一个小黄人倒下,另一个替补他的位置n

n

n 假设从浏览器点击快乐小黄人服务时得到的:n

n

n 图片 25n

n

n 如果杀死“happy-minion-58c9c46d67-j84s9”会发生什么们可以通过仪表板的Pods部分n n 删除nn :n

n

n n kubectl delete pod happy-minion-58c9c46d67-j84s9nn
n

n

n 如果你在浏览器中点击刷新几次(杀死小黄人兵可能需要一点时间),你会看到该服务会使用该类型的另一个小黄人。如果浏览Pods部分,您将看到Kubernetes创建了一个新的Pod来代替您删除的那个,以保证该部署中有两个节点。n

n

n 2.4读锁获取n

n

n 写锁的获取调用的是n n acquireShared(int arg)nn 方法:n

n

n 图片 26n

n

n 内部调用的是:n n doAcquireShared(arg);nn 方法(实现也是在Syn的),我们来看看:n

n

n 图片 27n

n

n Minion升级n

n

n 我们还可以为小黄人进行滚动升级。为此,我们应该在minions-army.yml文件的每个Deployment部分的’spec’部分下面(它可以直接位于同一级别的’replicas’下面):n

n

n “`n

n

n minReadySeconds: 10n

n

n strategy:n

n

n type: RollingUpdaten

n

n rollingUpdate:n

n

n maxUnavailable: 1n

n

n maxSurge: 1n

n

n “`n

n

n 然后将Controller类中的版本更改为0.2,保存它然后执行:n

n

n n docker build . -t minion:0.2nn
n

n

n 然后打开minion-army.yml并找到 – 用“0.2”替换所有“最新”,保存更改并执行:n

n

n n kubectl apply -f minion-army.yml --recordnn
n

n

n 刷新其中一个minion类型的浏览器,以查看版本更改是否与kubectl rollout status部署中看到的内容一致,其中<deployment_name>是minion类型(例如one-eyed-minion)。n

n

n 三、最后n

n

n 这里就简单总结一下本文的内容吧:n

n

  • n n AQS是n n ReentrantReadWriteLock和ReentrantLock的n n 基础n n ,因为默认的实现都是在内部类Syn中,而Syn是继承AQS的~n
  • n ReentrantReadWriteLock和ReentrantLock**都支持公平和非公平模式**,公平模式下会去看FIFO队列线程是否是在队头,而非公平模式下是没有的n
  • n ReentrantReadWriteLock是一个读写锁,如果读的线程比写的线程要多很多的话,那可以考虑使用它。它使用state的变量n n 高16位是读锁,低16位是写锁n n
  • n n 写锁可以降级为读锁,读锁不能升级为写锁n n
  • n n 写锁是互斥的,读锁是共享的n n 。n

n

n 总的来说看多线程源码难度系数还是好高啊,我目前的水平只能过一过了….n

n

n 多线程后面还有挺多高深的知识点:Future、同步容器啊、阻塞队列、各种n n 原子类nn 啊等等等,n n 这里我打算就先放一放了n n ,目前的水平有限啊~n

n

n 后面可能会有一篇n n 线程池nn 的博文,敬请期待咯~n

n

n 有兴趣的同学可继续往下面的参考资料下学习~~~n

n

n 参考资料:n

n

  • n n httpnn ://cmsblogs.com/?page_id=111n

n

n 如果n n 文章nn 有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以n n 关注n n 微信公众号nn :Java3yn n 。为了大家方便,刚新建了一下n n qq群:742919422n n ,大家也可以去交流交流。谢谢支持了!n n 希望nn 能多介绍给其他有需要的朋友n

","原文地址:Lock锁子类了解一下, 感谢原作者分享。"]

n 小黄人回滚n

n

n 要查看已部署的历史记录,请执行kubectl rollout history deployment <deployment_name>,回滚执行 kubectl rollout undo deployment <deployment_name> –to-revision = 1(可能需要一段时间)n

n

n 销毁军团n

n

n 用以下方法摧毁军队:n

n

n n kubectl delete -f minion-army.ymlnn
n

n

n 用“minikube stop”停止minikube。n

n

n 原文链接: Minions in Minikube – A Kubernetes Intro for Javan n Developernn s (n n 翻译nn :姜俊厚)n

","原文地址:Minikube中的小黄人 – 面向Java开发人员的Kubernetes简介, 感谢原作者分享。"]

本文由www.35222.com发布于澳门新葡京,转载请注明出处:剪夏罗根,Lock锁子类了然一下

关键词: www.35222.co

上一篇:澳门新葡京赤白散

下一篇:没有了

最火资讯