目录
Akka简介
Akka应用场景
Akka架构体系
Actor模型
体系结构
Actor组件
邮箱(Mailbox)
路由(Routing)
状态持久化( Persistence )
网络(远程和分布式集群)
HTTP 模块
相关开源项目
基本使用
环境搭建
Maven依赖
创建一个Actor
工厂模式
发送与接收消息
tell方法
ask方法
消息转发
查找Actor
消息不可变
Actor行为切换
Actor生命周期
创建并启动
恢复运行
重启
停止
停掉一个Actor
监督与容错处理
熔断(circuit breaker)
Close 状态
Open 状态
Half-Open 状态
配置
Akka简介
Akka 是一款高性能、高容错性的分布式&并行应用框架,遵循 Apache 2 开源许可,底层通过 JVM 上另外一个流行的语言 Scala 实现,提供Java&Scala API 。它基于经典的 Actor 并发模型(即所有的消息都是基于 Actor 组件进行传递),拥有如下特点:
并行与并发:提供对并行与并发的高度抽象。
异步非阻塞:Akka-Actor 消息通信都是基于异步非阻塞。
高容错性:为跨多 JVM 的分布式模型提供强劲的容错处理,号称永不宕机。
持久化:Actor 携带的状态或消息可以被持久化,以便于在 JVM 崩溃后能恢复状态。
轻量级:每个 Actor 大约只占 300bytes,即 1G 内存可容纳接近 300 万个 Actor。
基本上,Akka 从底层就解决了我们大多数分布式&并行程序常见的难题,让工程师更专注于业务实现,同时,它也保留了多个扩展接口及配置,便于满足个性化定制的需要!
Akka应用场景
目前 Akka 已经在多家互联网&软件公司广泛使用,比如 eBay、Amazon、VMWare、PayPal、阿里、惠普、豌豆荚等,涉及行业包括游戏、金融投资、医疗保健、数据分析等。
使用场景包括:
服务后端:比如 rest web,websocket 服务,分布式消息处理等。
并发&并行:比如日志异步处理,密集数据计算等。
总之,对高并发和密集计算的系统,Akka 都是适用的!
Akka架构体系
Akka 采用 Scala 开发,运行于 JVM 之上,提供了 Scala 和 Java 两种 API,目前属于 Lightbend 公司(原名 Typesafe)。它实现了经典的 Actor 模型,同时也提供了丰富的组件,比如邮箱(MailBox)、路由(Routing)、持久化( Persistence )、网络(包括远程、集群)等,在底层对分布式&并行模式进行了高度且统一的抽象,使工程师用很少的代码就可以实现一个完整的分布式应用。
Actor模型
Actor 模型最早在 1973 年由 Carl Hewitt 提出,它高度抽象了分布式并行程序的运行模式,从底层屏蔽了线程和锁机制的管理,为开发者提供了简单可依赖的开发方式。
Actor 模型认为,并行计算的最小单元就是一个 Actor 实例,而每个实例拥有自己的状态和行为,在一个大型系统中,可能存在成千上万个 Actor 实例,它们之间通过消息的方式进行通信,每个 Actor 都能发送消息给其他 Actor,也能从其他 Actor 接收消息。当我们在执行某个计算任务时,会给对应的 Actor 实例发送一个相关的消息,该 Actor 在接收消息后开始执行计算任务,由于整个消息通信的过程是异步的,所以不用等到 Actor 执行完整个过程就能执行下一步(发送消息后会马上返回),这种异步通信的方式大大提高了程序的响应性。
体系结构
Actor 是 Akka 最核心的概念,也是最基本的执行单元,所以对 Actor 管理和监控的有效性是极为重要的。在 Akka 中,每个 Actor 都有自己的监管对象,即该 Actor 的创建者,它们通常会负责子 Actor 的失败处理,另外,某些 Actor 也需要对生命周期进行监控(比如该 Actor 的终止),以便及时响应并做正确处理,这些监督和监控者本身也都是一个 Actor。在 Akka 中,整个 Actor 体系被抽象成一个 ActorSystem ,它是一个层级的结构,拥有公共行为的配置和管理。
在 ActorSystem 基础上,Akka 也提供了一些配套的组件,比如持久化,HTTP 服务,网络服务等,它们都是构建高可用分布式应用不可或缺的部分,基本架构体系和周边产品如下图所示。
Actor组件
在 Akka 中,Actor 是一个高度抽象的对象引用,它包含以下几个要素:
引用( Actor Reference ):Actor 的引用不同于普通对象的引用,也不能通过传统「new」的方式直接创建一个 Actor 对象。很多时候需要通过 actorOf 或者 actor-Selection 等方式返回一个ActorRef 对象,该对象有可能存在于本地,也可能存在于远程节点,对我们来说,它是位置透明的。Actor 之间的通信和执行任务都是通过消息驱动的(而不是 API 的调用)。
状态(State):Actor 在不同时刻可能有着不同的状态,这些状态用变量来表示。在底层实现上,Actor 是运行于线程池之上的,肯定会存在多个 Actor 共享同一个线程的情况,那么会不会出现并发问题呢?实际上,Akka 为每个 Actor 都抽象出一个轻量级的执行「线程」(不是真的线程),在底层已经实现了隔离,所以基本上不用担心该问题的出现。另外,当 JVM 崩溃时,为了避免 Actor 状态的丢失,我们可以借助持久化方案来对状态进行持久化操作。
行为(Behavior):Actor 有接收和发送消息的能力,每当它接收一条消息后,就可以执行某个业务操作,同时也可以把消息转发到其他节点进行处理。
监管策略( Supervisor Strategy ):Actor 系统是一个层级结构,当任务被某个 Actor 分摊到子 Actor 时,父 Actor 就拥有监管子 Actor 的义务。在监管时,我们需要根据不同的情况选择不同的处理方案(比如停止、重启、恢复或者失败上溯)和策略(比如 1 vs 1、1 vs N 策略)。
邮箱(Mailbox )
每个 Actor 都有自己的邮箱,所有其他 Actor 发送过来的消息都会进入该邮箱。Akka 自带多种邮箱类型,也提供自定义邮箱的接口。
路由(Routing)
消息除了通过普通的 Actor 发送之外,也可以通过路由发送。当通过路由发送消息时,我们可以根据需求来选择不同的路由策略,比如轮询、广播等。路由也可以是一个 Actor。
状态持久化( Persistence )
任何程序都有失败的可能,即便是 JVM 如此强大稳定的平台也一样。当程序出错、JVM 崩溃时,任何关键状态的丢失,对我们后续的业务来讲都可能是致命的打击,所以状态数据的持久化变得非常重要。Akka 提供了 Actor 状态的持久化方案,以便我们在必要时恢复数据。
网络(远程和分布式集群)
网络功能是实现远程 Actor 和分布式集群的基础,这其中包含 I/O、网络通信(TCP/UDP)、序列化配置、分布式通信协议(Gossip)、节点(node)管理、集群分片等内容。
HTTP 模块
Akka 提供了简单易用的 HTTP 模块,支持完整的 HTTP 服务端与客户端开发,可以帮助我们快速构建性能极强的 Rest Web 服务。
相关开源项目
Akka 具有高性能、可扩展、设计友好等诸多优点,非常适合用来作为分布式应用的基础框架,而且由于对 HTTP 有非常好的支持,也让它在 Web 服务领域占有一席之地。目前业界已经有多个基于 Akka 实现的开源项目,项目类型涵盖了 Web 开发、微服务、分布式文件或计算服务等。下面是 Akka 中两个具有代表性的开源项目:
Play 框架: 一款大名鼎鼎的 Web 开发框架。它不同于其他 Servlet 系的框架,比如 Struts 或者 SpringMVC ,底层基于 Akka 构建,天生拥有异步的特点,具有极佳的性能。它默认提供 RESTful 风格的 API,同时也对 WebSocket 有不错的支持。
Lagom 框架: 在目前 IT 界,最火爆的概念要属「微服务」了,微服务的理念是,把业务功能拆成小的、独立的单元,它们之间能够互相通信而且支持水平扩展。Lagom 就是这样一款微服务框架,它基于异步的消息驱动,对分布式集群、持久化(如 JPA、NoSQL)都有良好的支持。同时,它也拥有完整的集成开发环境,非常便于在线部署和管理。
基本使用
环境搭建
JDK版本最好是在 1.6 以上,不过后续会介绍Akka的一些新特性,所以最好采用1.8的版本。
Maven依赖
使用最新版akka依赖。
com.typesafe.akka
akka-actor_2.12
2.5.23
注意Akka中不同组件分为了不同的模块,我们这里暂时只是引用了核心模块,通过它可以使用akka的最基本功能。除开核心模块还包括akka-persistence 、akka-remote 、akka-cluster 等模块,分别用于实现持久化、远程、集群等功能。
创建一个Actor
public class ActorDemo extends AbstractActor {
private LoggingAdapter log = Logging.getLogger(this.getContext().getSystem(), this);
@Override
public Receive createReceive() {
return receiveBuilder()
.match(
String.class,
s -> log.info(s))
.matchAny(o -> {
log.info("any" + o.toString());
})
.build();
}
public static void main(String[] args) {
ActorSystem system = ActorSystem.create("sys");
ActorRef actorRef = system.actorOf(Props.create(ActorDemo.class), "actorDemo");
actorRef.tell("hello world", ActorRef.noSender()); // ActorRef.noSender()实际上就是叫做deadLetters的actor
}
}
通常每个应用程序只需要创建一个ActorSystem对象
在创建 ActorSystem 和 Actor 时,建议都指定名字,如果不知道akka将自动生成,在该示例中,它们的名字分别是 sys 和 actorDemo ,在同一个 ActorSystem 中 Actor 不能重名。
actorOf方法返回的不是Actor对象本身,而是ActorRef,表示Actor对象的引用。我们在向某个Actor发送消息时都是通过该引用进行的。
在Actor内部,可以使用getContext()来创建该Actor的子Actor,比如:ActorRef childActor=getContext().actorOf(Props.create(ChildActor.class),"childActor" );
工厂模式
ActorSystem 和 ActorContext 通过接收一个 Props 实例来创建 Actor,而 Props 实例本身有两种方式可以创建:
Props.create(ActorDemo.class, Object... args)
指定一个Props工厂。
对于比较简单的场景使用第一种就足够了,而如果需要按统一的规则创建Actor,我们可以在Actor内定义一个创建Props的方法,比如:
public static Props createProps() {
return Props.create(new Creator() {
@Override
public Actor create() throws Exception {
return new HelloWorldActor();
}
});
}
然后可以使用一下代码来创建Actor:
ActorRef actorRef = system.actorOf(ActorDemo.createProps(), "actorDemo");
可以看出,如果我们使用工厂模式,在创建Actor时调用工厂方法,我们不用关心Actor创建的具体过程了,有Actor自己封装即可。
发送与接收消息
Actor中的createReceive方法是用来接收并处理消息的。
createReceive方法需要放回Receive对象,而Receive对象就是真正用来处理消息的逻辑。
Receive对象可以定义规则使接收到的消息进入不同的处理逻辑:
match(Class type):消息类型为指定type的进入此分支
matchEquals(P object):消息值与object相等的进入此分支
matchAny():任何消息都可以进入到此分支
当然,一个消息只会进入到一个分支,如果一个消息匹配多个条件优先进入定义靠前的条件。
可以使用tell和ask两种方式发送消息,它们都以异步的方式发送消息,不同的是,前者发完后立即返回,而后者期待得到一个返回结果,假如在设置的时间(Timeout)内没有得到返回结果,发送方会收到一个超时异常。
tell方法
第一个参数即"消息",它可以是任何可序列化的数据或对象,第二个参数表示发送者,noSender()表示无发送者(实际上是一个叫做 deadLetters 的 Actor,后面介绍)。假如想在Actor内部得到发送者,可以调用getSender ()方法。
在调用 tell 方法后,Actor 就会异步的去处理该消息,并不会阻塞后续代码的运行。
ask方法
这是一种“请求-响应”模式,ask方法会将返回结果包装在scala.concurrent.Future中。
对于一个Actor如何将响应返回给消息发送者呢,其实就是想响应作为消息发送给请求消息的发送者:
getSender().tell( "hello " +msg , getSelf());
使用样例:
public class AskDemo extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder().matchAny(o -> {
System.out.println("发送者是" + getSender());
Thread.sleep(1000);
getSender().tell("hello " + o, getSelf());
}).build();
}
public static void main(String[] args) {
ActorSystem system = ActorSystem.create("sys");
ActorRef askActor = system.actorOf(Props.create(AskDemo.class), "askActorDemo");
Timeout timeout = new Timeout(Duration.create(2, TimeUnit.SECONDS));
Future f = Patterns.ask(askActor, "Akka Ask", timeout);
System.out.println("ask ...");
f.onSuccess(new OnSuccess() {
@Override
public void onSuccess(Object result) throws Throwable {
System.out.println("收到消息:" + result);
}
}, system.getDispatcher());
}
}
消息转发
Actor可以将接收到的消息转发给其他Actor,语法为:
static class ForwardActor extends AbstractActor {
private ActorRef target = getContext().actorOf(Props.create(TargetActor.class), "targetActor");
@Override
public Receive createReceive() {
return receiveBuilder().matchAny((message) -> {
target.forward(message, getContext());
}).build();
}
}
TargetActor接收到转发过来的消息后,发送者任然是消息原始的发送者,而不是转发者。
查找Actor
对于已存在的 Actor,我们可以根据路径来进行查找,API 如下:
ActorSelection as = [ActorSystem/ActorContext].actorSelection([path]);
在调用它时,必须指定一个绝对或者相对路径(包括远程路径),比如:
/user/parentActor/childActor
../parentActor/childActor
akka.tcp://testuser@127.0.0.1:2554/user/parentActor/childActor
查找结果为ActorSelection,表示一个或多个Actor,所以向ActorSelection发送消息时,对应的一个或多个Actor都将接收到消息。
消息不可变
Akka中都是消息驱动的,所以消息是非常重要。理论上,Actor 可以传递或接收任何类型的消息,但是为了避免出现竞态条件(对共享资源的并发写)和不可预知的数据篡改,最好把消息设计成不可变的对象。在该对象中,我们通常会把所有变量设计成只读,在该对象的整个生命周期内,这些数据将不可修改。所以在 Java 中,我们借助final 关键字来实现。
对于集合框架,有必要通过 Collections.unmodifiable 系列的 API 来保证不变性。Collections.unmodifiable 内部使用 UnmodifiableList 、UnmodifiableMap 等 API 对现有的集合进行包装,它们通过重写其中的 set、add、put 等方法来达到限制数据修改的目的。
Actor行为切换
在业务处理过程中,往往会面临一些关键数据的变化,而这些变化也会进一步影响着程序的执行逻辑,很多时候,我们把这些关键数据称之为「状态」。状态的处理需要依赖于具体的业务,而业务本身也可能充满不确定性,一种比较好的做法是,我们把多个状态的处理过程(即行为)封装起来,形成一个个独立的组件,在使用时就可以很方便地组装、重用或切换。在 Actor 中,行为可以通过Receive来定义,一旦抽取完我们所需要的Receive,就可以使用 become/unbecome 方法来切换他们,其中 become 表示切换为某个行为,unbecome 表示修改回上一个行为。
Actor生命周期
Actor 在运行时中会经历不同的阶段,比如创建、运行、重启和销毁等,这一系列的过程或状态,我们称之为生命周期。在理想情况下,Actor 应该像一头老黄牛一样任劳任怨地不停工作,但实际情况往往是,当某个不算常态的错误发生时(比如网络偶尔超时),我们想让它重启一下,然后重复之前的动作;又或者,当一个程序异常被抛出时,我们不得不停止该 Actor,让它不能继续走下去,这些行为有可能是手动触发的,也可能是 Actor 的监督-容错机制导致的。无论怎样,当这些行为发生时,我们都希望能及时感知并做有效处理。
Actor 生命周期主要包括启动(Start)、恢复(Resume)、重启(Restart)、停止(Stop)这四个阶段,每个阶段都会伴随着自身状态信息的变化。
创建并启动
当通过 actorOf 创建并启动 Actor 时,该 Actor 除了默认拥有已指定的 path 外,也会被分配一个 UID(可以通过 getSelf().path().uid()得到该值),作为它的唯一标识。在 Actor 启动后,会默认调用 preStart 方法,在该方法里,我们可以做些资源初始化的操作。
恢复运行
当 Actor 出现某种异常后,通过容错机制,可以让该 Actor 恢复并继续运行,此时 Actor 会延用之前的实例,状态也会被保留下来。
重启
当 Actor 出现某种异常后,通过容错机制,可以让该 Actor 执行重启。重启的具体过程如下:
调用旧实例的 preRestart 方法,该方法默认情况下会停掉所有子级 Actor,并调用 postStop 方法;
创建新实例,并在新实例上调用 postRestart 方法,该方法默认情况下会调用 preStart 方法。
Actor 重启后,path 和 UID 不变,这意味着假如要继续使用该 Actor,不需要重新获取 ActorRef 对象,使用之前那个就可以了。同时也得注意到:Actor 重启后不会保留自身状态。
停止
当 Actor 停止时,会调用 postStop 方法,同时会发送一条 Terminated信息给自己的监控者,告知自己已处于停止状态。
停掉一个Actor
停止 Actor 大致有三种方式,它们分别是:
调用 ActorSystem 或者 getContext() 的 stop 方法;
给 Actor 发送一个 PoisonPill (毒丸)消息;
给 Actor 发送一个 Kill 的消息,此时会抛出ActorKilledException 异常,并上报到父级 supervisor 处理。
Actor 在停止时都会遵循一套比较可靠的流程:
当停止 Actor 时,正在处理的消息会在完全停止之前处理完毕,后续信息将不再进行处理,邮箱(用来保存 Actor 的消息)将被挂起;
给所有子级 Actor 发送终止指令,当子级都停掉后,再停掉自己,停止完毕后会调用 postStop 方法,在这里可以清理或释放资源;
向生命周期监控者( DeathWatch )发送 Terminated 消息,以便监控者做相应的处理。
可以使用getContext().watch();方法监控某个节点的停止信息,当该节点停止后,监控者会接收到一个Terminated消息。
监督与容错处理
Actor 系统采用"父监督"的模式进行管理,即父 Actor 会监督子 Actor 的异常情况,然后根据默认或者预设的处理逻辑来确定到底是该恢复 Actor、停止 Actor、重启 Actor 还是把错误上溯到父级。
Akka 提供了两种监督策略,分别是 One-For-One Strategy 和 All-For-One Strategy ,前者表示当一个子 Actor 出现异常时,只对该 Actor 做处理,后者则表示对所有子 Actor 都做处理,大部分时候应该选择 One-For-One Strategy (这也是默认的策略),除非子 Actor 之间的业务有很强的关联或者互相依赖。当程序中没有显式指定策略时,会启动一个默认策略:
当抛出 ActorInitializationException 和 ActorKilledException时,会终止子 Actor;
当抛出 Exception 时,会重启子 Actor;
抛出其他类型的 Throwable 异常时,会上溯失败到父级。
在 Actor 执行任务时可能会抛出不同类型的异常,很多时候,我们应该知道,哪些异常需要让 Actor 停止或重启,哪些异常可以「视而不见」。为了更加细化这种判断,我们需要自定义监督逻辑。
自定义一个监督逻辑非常简单,只需要在父 Actor 中创建一个SupervisorStrategy 对象,并通过 supervisorStrategy ()方法返回出来.
熔断(circuit breaker)
当一个Actor出现异常时,如果用户还继续向这个Actor发送消息,很有可能这个消息还是无法被处理,还额外的增加了服务器的压力,Akka中提供了熔断机制(circuit breaker)。
Circuit Breaker 状态图(图片来自 Akka 官网)
circuit breaker有三个状态,分别是:Closed、Open、Half-Open。
Close 状态
正常情况下,circuit breaker是closed状态:Actor出现异常或调用超过配置的callTimeout,就增加一次失败计数;
成功则重置失败计数为 0;
当失败次数达到maxFailures后,circuit breaker会进入Open状态。
Open 状态
Actor接收到的所有调用将抛出 CircuitBreakerOpenException ,立即失败;
在resetTimeout后,circuit breaker 进入Half-Open状态。
Half-Open 状态
第一次调用将尝试运行而不会快速失败;
如果第一个调用成功,会重回 Closed 状态;
如果第一个调用失败,会进入 Open 状态,然后等待下一次resetTimeout 。
配置
Akka 程序在启动时会加载一些默认的配置项,所以我们不需要显式地提供配置文件,假如要个性化配置某些行为,则需要新建配置文件。在默认情况下,程序会加载 classpath 下的 application.conf 、application.json 、application.properties 文件。
在创建ActorSystem 时,可以显式加载自定义的配置文件,比如app.conf ,代码如下:
ActorSystem system = ActorSystem.create( "myapp",ConfigFactory.load( "app.conf" ));
Akka 提供的配置项涵盖了几乎所有的核心功能,比如日志、远程、路由、消息序列化、分布式集群等.
你可能感兴趣的:(并发编程)
Java进阶指南:高级面试问题与精辟解答(一)
Xs_layla
java 面试题分享 java 面试 开发语言
Java面试问题及答案1.请解释什么是Java内存模型(JMM)?它在并发编程中扮演什么角色?答案:Java内存模型(JMM)是一个抽象的内存模型,它定义了Java程序中变量的访问规则,以及在并发环境下如何保证内存操作的原子性、可见性和有序性。JMM确保了在多线程环境下,不同线程间对共享变量的读写操作能够按照一定的顺序进行,从而避免数据竞争和不一致的问题。在并发编程中,JMM扮演着至关重要的角色。
yield方法释放锁吗_JUC 并发编程.md
月宫一号
yield方法释放锁吗
#多线程进阶---->JUC编程准备环境,IDEA新建一个Maven项目,然后环境设置jdk8#1、什么是JUCJUC就是以上的三个包(面试高频问题JUC)java.uitljava中
JUC并发编程之集合类线程安全问题
xzystart
JUC并发编程 java 集合 线程安全 多线程 并发编程
在并发条件下,由于多数集合没有同步控制所以这些集合具有线程不安全性线程不安全的集合线程不安全用例(ArrayList为例)示例publicclassMainTest{publicstaticvoidmain(String[]args){ArrayListarrayList=newArrayList{arrayList.add(UUID.randomUUID().toString());System
JUC并发—9.并发安全集合三
东阳马生架构
JUC并发原理及源码 JUC并发 Java 并发安全的集合
大纲1.并发安全的数组列表CopyOnWriteArrayList2.并发安全的链表队列ConcurrentLinkedQueue3.并发编程中的阻塞队列概述4.JUC的各种阻塞队列介绍5.LinkedBlockingQueue的具体实现原理6.基于两个队列实现的集群同步机制1.并发安全的数组列表CopyOnWriteArrayList(1)CopyOnWriteArrayList的初始化(2)基
深入理解 ABA 问题与退让策略:Go 语言实现与优化
老赵不会写代码
go语言 golang 开发语言 后端
深入理解ABA问题与退让策略:Go语言实现与优化在并发编程中,无锁数据结构(Lock-FreeDataStructures)因其高性能和避免死锁的特性而备受关注。然而,实现无锁算法时,开发者常常会遇到ABA问题和退让策略这两个关键问题。本文将详细解释这两个问题,并结合Go语言提供具体的实现示例。一、ABA问题1.问题定义ABA问题是CAS(Compare-And-Swap)操作中一个经典陷阱。当某
Go语言通关指南:零基础玩转高并发编程(第Ⅲ部分)(第6章)-函数编程
双囍菜菜
golang 开发语言 后端
Go语言通关指南:零基础玩转高并发编程(第Ⅲ部分)(第6章)-函数编程文章目录Go语言通关指南:零基础玩转高并发编程(第Ⅲ部分)(第6章)-函数编程第Ⅲ部分核心编程范式第6章函数编程6.1函数声明与参数传递6.1.1函数签名规范6.1.2高性能参数模式6.1.3面试题解析6.2多返回值与错误处理6.2.1错误处理范式演进6.2.2错误包装与追踪6.2.3面试题解析6.3匿名函数与闭包6.3.1闭包
面试八股文--并发编程篇
汤汤upup
面试八股文 面试 职场和发展 并发编程
一、线程和进程1、线程和进程的定义进程:是资源分配的最小单位,是指计算机中正在运行的一个实例,如你打开了浏览器就是打开了一个进程。线程:是程序运行的最小单位。一个进程中包含多个线程,他们可以共享进程的进程的资源比如内存空间、文件句柄等。2、线程和进程的区别进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间线程更轻量
《Java高并发与多线程:从原理“破壁”到实战“狂飙”的硬核攻略》
以恒1
java
Java必学,看一眼不吃亏,万一对你有用呢,本文万字解析进程与线程本质,讲解了多线程和高并发的原理,详解synchronized锁升级机制,剖析JUC工具库与线程池异步,结合实时监控,电力调控等高并发场景,提供线程池调优、分布式锁(Redis)等实战方案,贯通原理到工程的全链路知识。一、操作系统基础:理解并发编程的根基1.进程与线程的本质区别官方定义:进程是操作系统资源分配的基本单位,每个进程拥有
Go语言通关指南:零基础玩转高并发编程(第Ⅱ部分)(第4章)-流程控制
双囍菜菜
后端 golang
Go语言通关指南:零基础玩转高并发编程(第Ⅱ部分)(第4章)-流程控制文章目录Go语言通关指南:零基础玩转高并发编程(第Ⅱ部分)(第4章)-流程控制第Ⅱ部分语言基础篇第4章流程控制4.1条件语句(if/switch)4.1.1if语句的精简之道4.1.2switch的灵活扩展4.1.3与C/Java的差异对比4.1.4性能优化技巧4.2循环结构(for/range)4.2.1for循环的三种形态4
Future和FutureTask实现类详解以及使用。
一个儒雅随和的男子
多线程 java
前言Future是Java并发编程中的一个接口,用来表示异步计算的结果。它允许我们提交一个任务,然后之后再去获取结果,或者在结果可用时处理它。我们需要考虑Future的主要方法。根据文档,Future接口有几个关键方法:isDone()检查计算是否完成,get()获取结果(会阻塞直到完成),cancel()尝试取消任务,isCancelled()判断是否被取消。这些方法的作用和用法需要详细说明。然
Spring Bean 如何保证并发安全???
G丶AEOM
八股 普通学习区 java 八股 spring
SpringBean如何保证并发安全简单来说:1、可以设置Beon的作用域为原型,这样每次从容器中获取该Bean时,都会创建一个新的实例,避免了多线程共享同一个对象实例的问题2、在不改变Beon的作用域的情况下,可以避免在Beon中存在可变状态的声明,尽量将状态信息存在方法内部的局部变量中,或者使用线程安全的数据结构,如ConcurrentHashMap来管理状态3、使用Java并发编程中提供的锁
Go语言通关指南:零基础玩转高并发编程(第Ⅰ部分)(第1、2章)-初识Go语言
caishuangxi111
golang 开发语言 后端
Go语言通关指南:零基础玩转高并发编程(第Ⅰ部分)(第1、2章)-初识Go语言文章目录Go语言通关指南:零基础玩转高并发编程(第Ⅰ部分)(第1、2章)-初识Go语言前言第Ⅰ部分初识Go语言第1章Go语言概述1.1Go的诞生与发展历程1.1.1诞生背景1.1.2发展里程碑1.1.3设计哲学解析1.2核心设计哲学与特性1.2.1六大核心设计原则1.2.2关键语言特性1.2.3设计取舍的艺术1.3Go与
Java高级开发所具知识技能
码代码的小仙女
java知识 高级开发必备技能 java 开发语言
以下是Java高级开发整理的知识技能,其中涵盖核心技术、框架、分布式架构、性能优化等关键领域:一、Java核心进阶JVM深度理解内存模型(堆、栈、方法区)垃圾回收算法(CMS、G1、ZGC)类加载机制与字节码增强JVM调优工具(jstat、jmap、VisualVM、Arthas)并发编程线程池(ThreadPoolExecutor、ForkJoinPool)锁机制(synchronized、Re
2025年Java高级工程师面试题精选:30道高频问题深度解析
emmm形成中
java 开发语言 面试
2025年Java高级工程师面试题精选:30道高频问题深度解析在Java高级工程师的面试中,技术深度和广度是考察的重点。本文整理了30道高频面试题,涵盖Java基础、JVM、并发编程、集合框架、Spring框架等核心知识点,帮助你在面试中脱颖而出。一、Java基础1.Java面向对象的三大特征是什么?如何应用?答案:封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式。继承:子类继承父类的属性和
Go、Java、Python、C/C++、PHP、Rust 语言全方位对比分析
tekin
Go 语言攻坚营 Python 编程秘籍库 java golang java c++ 编程语言对比 Python 语言 PHP 语言 编程适用场景
简介在当今多元化的编程世界中,不同的编程语言各有千秋,适用于不同的应用场景。本文聚焦于Go、Java、Python、C/C++、PHP和Rust这六种热门编程语言,深入剖析它们的优劣势以及各自的最佳适用场景,旨在为开发者在选择合适的编程语言时提供全面、准确的参考依据。语言优势对比语言优势劣势最佳适用场景Go1.高性能,编译速度快,执行效率接近C/C++。2.强大的并发编程支持,goroutine和
第一个Go语言程序——Hello world
「已注销」
GOLANG 笔记 golang 开发语言 后端
Go语言简介Go语言(也被称为Golang)是一门开源的编程语言,由Google开发并于2009年首次发布;它在设计上强调简单性、高效性和安全性,旨在提高程序员的生产力和代码可读性。Go语言的设计主要针对高并发、高性能和简单的编程;具有良好的内存管理和垃圾回收机制,支持并发编程,可以轻松地使用多核CPU。Go语言官网GO语言中文网Go语言的特点简单易学:Go语言的语法简洁明了,易于学习和使用。高并
Python 的 WebSocket 实现详解
王子良.
经验分享 python websocket 网络协议 网络
欢迎来到我的博客!非常高兴能在这里与您相遇。在这里,您不仅能获得有趣的技术分享,还能感受到轻松愉快的氛围。无论您是编程新手,还是资深开发者,都能在这里找到属于您的知识宝藏,学习和成长。博客内容包括:Java核心技术与微服务:涵盖Java基础、JVM、并发编程、Redis、Kafka、Spring等,帮助您全面掌握企业级开发技术。大数据技术:涵盖Hadoop(HDFS)、Hive、Spark、Fli
Go 错误处理与调试:面向对象的入门教程
一小路一
掌握 Go 语言:编程世界的进阶钥匙 golang 开发语言 后端 面试
Go错误处理与调试:面向对象的入门教程Go语言因其简洁、高效和易于并发编程的特性,逐渐成为后端开发的主流语言之一。错误处理是任何编程语言中非常重要的一部分,尤其是在Go语言中,Go提供了一种不同于传统异常处理机制的错误处理方式。理解Go的错误处理和调试技巧,对开发者而言是非常必要的。在本文中,我们将讨论Go语言的错误处理机制、调试技巧,并通过一些示例帮助大家理解错误处理的最佳实践,此外还会列出一些
Python 并发编程实战:优雅地使用 concurrent.futures
python
在Python多线程编程中,concurrent.futures模块提供了一个高层的接口来异步执行可调用对象。今天,我们将通过一个循序渐进的案例,深入了解如何使用这个强大的工具。从一个模拟场景开始假设我们需要处理一批网络请求。为了模拟这个场景,我们使用sleep来代表耗时操作:importtimeimportrandomdefslow_operation(task_id):"""模拟一个耗时的网络
GO语言并发编程之channel
新青年579
golang 数据库 后端
前言入职公司三四个月,本质上做的都是CMS(内容系统管理)的内容,这类系统一般用于创建、管理和发布内容,通常包括但不限于文本、图像、视频等。,但是内容管理系统的读取操作可能相对较多,但更新、发布内容、审核等操作的频率较低,因此在大部分时间内并不会造成高并发压力。但是我们以后肯定会接触到高并发场景的业务的,我们先对GO语言中的channel有一个了解吧。Channel是什么?Channel(通道)是
Java并发编程入门,看这一篇就够了
weixin_30555753
java 数据库 人工智能
Java并发编程一直是Java程序员必须懂但又是很难懂的技术内容。这里不仅仅是指使用简单的多线程编程,或者使用juc的某个类。当然这些都是并发编程的基本知识,除了使用这些工具以外,Java并发编程中涉及到的技术原理十分丰富。于是乎,就诞生了想写点东西记录下,以提升理解和对并发编程的认知。为什么需要用到并发?凡事总有好坏两面,之间的trade-off是什么,也就是说并发编程具有哪些挑战?以及在进行并
JMM(Java内存模型)讲解
十五001
基础 java jvm
JMM(JavaMemoryModel,Java内存模型)是Java并发编程中的一个非常重要的概念,它帮助我们理解Java程序在多线程环境下内存操作的行为。别担心,我会用简单易懂的方式来讲解,让你轻松掌握它的核心内容。1.什么是JMM?定义JMM是Java内存模型的简称,它定义了Java程序中内存操作的规则和规范。简单来说,JMM规定了Java程序中的变量存储在内存中的方式,以及线程如何读取和写入
【Python系列】Python 解释器的站点配置
Kwan的解忧杂货铺@新空间代码工作室
s1 Python python 开发语言
欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。推荐:kwan的首页,持续学习,不断总结,共同进步,活到老学到老导航檀越剑指大厂系列:全面总结java核心技术点,如集合,jvm,并发编程redis,kafka,Spring,微服务,Netty等常用开发工具系列:罗列常用的开发工具,如IDEA,M
解密Python协程:提升并发编程效率的秘籍
爪哇抓挖_Java
日常 python
在现代软件开发中,提升程序的执行效率和响应速度是每个开发者的追求。Python的协程是并发编程领域中的一个强大工具,能显著优化I/O密集型任务和高延迟操作的处理。本篇博客将详细介绍Python协程的工作原理和应用方法,通过具体的代码示例帮助开发者掌握这一技术。###Python协程简介协程,或称微线程,是一种用户态的轻量级线程,Python的协程通过`asyncio`库实现。与传统线程相比,协程在
python 协程 深入浅出
秋裤傻
python 多线程 java linux 多进程
说到并发编程,大家容易想到的就是:进程、线程、协程、异步IO。四者在实现上却有共通之处,不外乎调度二字。进程:操作系统进程系统调度,调度号:pid,基本由操作系统提供调度支持线程:操作系统线程调度,调度号:TCB,虚拟机提供一部分支持协程:程序自己进行调度,调度号:函数名,全部由程序自身完成。异步IO:由消息中间件负责调度,调度号:消息队列。进程、线程、协程它们三个实现的是时间复用,达到逻辑上的同
深入浅出:Go 语言的学习之路
软件架构师笔记
golang golang 学习 开发语言
文章目录1.Go语言简介2.Go语言的安装与环境配置2.1安装Go2.2配置开发环境3.Go语言基础语法3.1变量与数据类型示例代码:定义变量3.2控制结构示例代码:条件语句示例代码:循环语句3.3函数与方法示例代码:定义函数示例代码:定义方法4.并发编程4.1Goroutines示例代码:使用Goroutines4.2Channels示例代码:使用Channels5.面向对象编程5.1结构体与方
C#编程的技术难点有什么
编程
在C#编程的过程中,开发者会面临许多技术难点,尤其是在深入理解和应用C#的高级特性时。C#编程的技术难点主要体现在内存管理、并发编程、反射机制、LINQ(语言集成查询)、以及异步编程等方面。这些难点往往需要开发者对C#的底层原理和高级功能有较为深入的理解,并且在实际项目中逐步积累经验。其中,异步编程与并发编程是C#开发中常见且具挑战性的难点,特别是在多线程和任务并行的处理上,需要合理运用相关的工具
【Linux探索学习】第二十九弹——线程概念:Linux线程的基本概念与线程控制详解
GG Bond.ฺ
Linux探索学习 linux 学习 算法 运维
Linux学习笔记:https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482前言:在现代操作系统中,线程是程序执行流的最小单元。与进程相比,线程更加轻量级,创建和销毁的开销更小,且线程之间可以共享内存空间,因此在多任务处理、并发编程中,线程的使用非常广泛。Linux作为一个多用户、多任务的操
并发编程利器 - CountDownLatch
小马不敲代码
Java 并发编程
什么是CountDownLatch?CountDownLatch是Java并发包(java.util.concurrent)中的一个实用类,它允许一个或多个线程等待其他线程完成一组操作。CountDownLatch在初始化时设置一个计数值(count),这个值表示需要等待完成的操作数量。每当一个操作完成时,CountDownLatch的计数就会减1。当计数到达0时,等待的线程就会被唤醒,继续执行后
并发编程利器 - Future 接口
小马不敲代码
Java 并发编程
一、背景介绍对于线程池来说,任务执行类只需要实现Runnable接口,然后交给线程池,就可以轻松的实现异步执行多个任务的目标,提升程序的执行效率,比如如下异步执行任务下载。//创建一个线程池ExecutorServiceexecutor=Executors.newFixedThreadPool(2);//提交任务executor.submit(newRunnable(){@Overridepubl
多线程编程之理财
周凡杨
java 多线程 生产者 消费者 理财
现实生活中,我们一边工作,一边消费,正常情况下会把多余的钱存起来,比如存到余额宝,还可以多挣点钱,现在就有这个情况:我每月可以发工资20000万元 (暂定每月的1号),每月消费5000(租房+生活费)元(暂定每月的1号),其中租金是大头占90%,交房租的方式可以选择(一月一交,两月一交、三月一交),理财:1万元存余额宝一天可以赚1元钱,
[Zookeeper学习笔记之三]Zookeeper会话超时机制
bit1129
zookeeper
首先,会话超时是由Zookeeper服务端通知客户端会话已经超时,客户端不能自行决定会话已经超时,不过客户端可以通过调用Zookeeper.close()主动的发起会话结束请求,如下的代码输出内容
Created /zoo-739160015
CONNECTEDCONNECTED
.............CONNECTEDCONNECTED
CONNECTEDCLOSEDCLOSED
SecureCRT快捷键
daizj
secureCRT 快捷键
ctrl + a : 移动光标到行首ctrl + e :移动光标到行尾crtl + b: 光标前移1个字符crtl + f: 光标后移1个字符crtl + h : 删除光标之前的一个字符ctrl + d :删除光标之后的一个字符crtl + k :删除光标到行尾所有字符crtl + u : 删除光标至行首所有字符crtl + w: 删除光标至行首
Java 子类与父类这间的转换
周凡杨
java 父类与子类的转换
最近同事调的一个服务报错,查看后是日期之间转换出的问题。代码里是把 java.sql.Date 类型的对象 强制转换为 java.sql.Timestamp 类型的对象。报java.lang.ClassCastException。
代码:
可视化swing界面编辑
朱辉辉33
eclipse swing
今天发现了一个WindowBuilder插件,功能好强大,啊哈哈,从此告别手动编辑swing界面代码,直接像VB那样编辑界面,代码会自动生成。
首先在Eclipse中点击help,选择Install New Software,然后在Work with中输入WindowBui
web报表工具FineReport常用函数的用法总结(文本函数)
老A不折腾
finereport web报表工具 报表软件 java报表
文本函数
CHAR
CHAR(number):根据指定数字返回对应的字符。CHAR函数可将计算机其他类型的数字代码转换为字符。
Number:用于指定字符的数字,介于1Number:用于指定字符的数字,介于165535之间(包括1和65535)。
示例:
CHAR(88)等于“X”。
CHAR(45)等于“-”。
CODE
CODE(text):计算文本串中第一个字
mysql安装出错
林鹤霄
mysql安装
[root@localhost ~]# rpm -ivh MySQL-server-5.5.24-1.linux2.6.x86_64.rpm Preparing... #####################
linux下编译libuv
aigo
libuv
下载最新版本的libuv源码,解压后执行:
./autogen.sh
这时会提醒找不到automake命令,通过一下命令执行安装(redhat系用yum,Debian系用apt-get):
# yum -y install automake
# yum -y install libtool
如果提示错误:make: *** No targe
中国行政区数据及三级联动菜单
alxw4616
近期做项目需要三级联动菜单,上网查了半天竟然没有发现一个能直接用的!
呵呵,都要自己填数据....我了个去这东西麻烦就麻烦的数据上.
哎,自己没办法动手写吧.
现将这些数据共享出了,以方便大家.嗯,代码也可以直接使用
文件说明
lib\area.sql -- 县及县以上行政区划分代码(截止2013年8月31日)来源:国家统计局 发布时间:2014-01-17 15:0
哈夫曼加密文件
百合不是茶
哈夫曼压缩 哈夫曼加密 二叉树
在上一篇介绍过哈夫曼编码的基础知识,下面就直接介绍使用哈夫曼编码怎么来做文件加密或者压缩与解压的软件,对于新手来是有点难度的,主要还是要理清楚步骤;
加密步骤:
1,统计文件中字节出现的次数,作为权值
2,创建节点和哈夫曼树
3,得到每个子节点01串
4,使用哈夫曼编码表示每个字节
JDK1.5 Cyclicbarrier实例
bijian1013
java thread java多线程 Cyclicbarrier
CyclicBarrier类
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环的 barrier。
CyclicBarrier支持一个可选的 Runnable 命令,
九项重要的职业规划
bijian1013
工作 学习
一. 学习的步伐不停止 古人说,活到老,学到老。终身学习应该是您的座右铭。 世界在不断变化,每个人都在寻找各自的事业途径。 您只有保证了足够的技能储
【Java范型四】范型方法
bit1129
java
范型参数不仅仅可以用于类型的声明上,例如
package com.tom.lang.generics;
import java.util.List;
public class Generics<T> {
private T value;
public Generics(T value) {
this.value =
【Hadoop十三】HDFS Java API基本操作
bit1129
hadoop
package com.examples.hadoop;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoo
ua实现split字符串分隔
ronin47
lua split
LUA并不象其它许多"大而全"的语言那样,包括很多功能,比如网络通讯、图形界面等。但是LUA可以很容易地被扩展:由宿主语言(通常是C或 C++)提供这些功能,LUA可以使用它们,就像是本来就内置的功能一样。LUA只包括一个精简的核心和最基本的库。这使得LUA体积小、启动速度快,从 而适合嵌入在别的程序里。因此在lua中并没有其他语言那样多的系统函数。习惯了其他语言的字符串分割函
java-从先序遍历和中序遍历重建二叉树
bylijinnan
java
public class BuildTreePreOrderInOrder {
/**
* Build Binary Tree from PreOrder and InOrder
* _______7______
/ \
__10__ ___2
/ \ /
4
openfire开发指南《连接和登陆》
开窍的石头
openfire 开发指南 smack
第一步
官网下载smack.jar包
下载地址:http://www.igniterealtime.org/downloads/index.jsp#smack
第二步
把smack里边的jar导入你新建的java项目中
开始编写smack连接openfire代码
p
[移动通讯]手机后盖应该按需要能够随时开启
comsci
移动
看到新的手机,很多由金属材质做的外壳,内存和闪存容量越来越大,CPU速度越来越快,对于这些改进,我们非常高兴,也非常欢迎
但是,对于手机的新设计,有几点我们也要注意
第一:手机的后盖应该能够被用户自行取下来,手机的电池的可更换性应该是必须保留的设计,
20款国外知名的php开源cms系统
cuiyadll
cms
内容管理系统,简称CMS,是一种简易的发布和管理新闻的程序。用户可以在后端管理系统中发布,编辑和删除文章,即使您不需要懂得HTML和其他脚本语言,这就是CMS的优点。
在这里我决定介绍20款目前国外市面上最流行的开源的PHP内容管理系统,以便没有PHP知识的读者也可以通过国外内容管理系统建立自己的网站。
1. Wordpress
WordPress的是一个功能强大且易于使用的内容管
Java生成全局唯一标识符
darrenzhu
java uuid unique identifier id
How to generate a globally unique identifier in Java
http://stackoverflow.com/questions/21536572/generate-unique-id-in-java-to-label-groups-of-related-entries-in-a-log
http://stackoverflow
php安装模块检测是否已安装过, 使用的SQL语句
dcj3sjt126com
sql
SHOW [FULL] TABLES [FROM db_name] [LIKE 'pattern']
SHOW TABLES列举了给定数据库中的非TEMPORARY表。您也可以使用mysqlshow db_name命令得到此清单。
本命令也列举数据库中的其它视图。支持FULL修改符,这样SHOW FULL TABLES就可以显示第二个输出列。对于一个表,第二列的值为BASE T
5天学会一种 web 开发框架
dcj3sjt126com
Web 框架 framework
web framework层出不穷,特别是ruby/python,各有10+个,php/java也是一大堆 根据我自己的经验写了一个to do list,按照这个清单,一条一条的学习,事半功倍,很快就能掌握 一共25条,即便很磨蹭,2小时也能搞定一条,25*2=50。只需要50小时就能掌握任意一种web框架
各类web框架大同小异:现代web开发框架的6大元素,把握主线,就不会迷路
建议把本文
Gson使用三(Map集合的处理,一对多处理)
eksliang
json gson Gson map Gson 集合处理
转载请出自出处:http://eksliang.iteye.com/blog/2175532 一、概述
Map保存的是键值对的形式,Json的格式也是键值对的,所以正常情况下,map跟json之间的转换应当是理所当然的事情。 二、Map参考实例
package com.ickes.json;
import java.lang.refl
cordova实现“再点击一次退出”效果
gundumw100
android
基本的写法如下:
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
//navigator.splashscreen.hide();
document.addEventListener("b
openldap configuration leaning note
iwindyforest
configuration
hostname // to display the computer name
hostname <changed name> // to change
go to: /etc/sysconfig/network, add/modify HOSTNAME=NEWNAME to change permenately
dont forget to change /etc/hosts
Nullability and Objective-C
啸笑天
Objective-C
https://developer.apple.com/swift/blog/?id=25
http://www.cocoachina.com/ios/20150601/11989.html
http://blog.csdn.net/zhangao0086/article/details/44409913
http://blog.sunnyxx
jsp中实现参数隐藏的两种方法
macroli
JavaScript jsp
在一个JSP页面有一个链接,//确定是一个链接?点击弹出一个页面,需要传给这个页面一些参数。//正常的方法是设置弹出页面的src="***.do?p1=aaa&p2=bbb&p3=ccc"//确定目标URL是Action来处理?但是这样会在页面上看到传过来的参数,可能会不安全。要求实现src="***.do",参数通过其他方法传!//////
Bootstrap A标签关闭modal并打开新的链接解决方案
qiaolevip
每天进步一点点 学习永无止境 bootstrap 纵观千象
Bootstrap里面的js modal控件使用起来很方便,关闭也很简单。只需添加标签 data-dismiss="modal" 即可。
可是偏偏有时候需要a标签既要关闭modal,有要打开新的链接,尝试多种方法未果。只好使用原始js来控制。
<a href="#/group-buy" class="btn bt
二维数组在Java和C中的区别
流淚的芥末
java c 二维数组 数组
Java代码:
public class test03 {
public static void main(String[] args) {
int[][] a = {{1},{2,3},{4,5,6}};
System.out.println(a[0][1]);
}
}
运行结果:
Exception in thread "mai
systemctl命令用法
wmlJava
linux systemctl
对比表,以 apache / httpd 为例 任务 旧指令 新指令 使某服务自动启动 chkconfig --level 3 httpd on systemctl enable httpd.service 使某服务不自动启动 chkconfig --level 3 httpd off systemctl disable httpd.service 检查服务状态 service h