首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Dart 入门教程

[TOC] 一、开篇 dart 语言具有如下特性 一切变量皆是对象,每个对象都是类的实例。int、double、函数、 null 等都是对象,所有对象都继承自 Object 类 dart 是强类型语言,但由于具备类型推导功能所以类型声明是可选的 dart 支持顶级函数、静态函数、实例函数,也允许在函数中嵌套函数,即局部函数。类似的,dart 也支持顶级变量、静态变量和实例变量 dart 没有关于 public、protected、private 的关键字。通过为变量标识符添加下划线前缀,表明该标识符对其库是私有的 .... 先来看个小例子 /** * 多行注释 */ void printString(String msg) { print("msg value: $msg"); } void main() { var msg = "H

优秀的个人博客,低调大师

Docker入门-数据挂载

Docker数据管理 在容器中管理数据主要有两种方式: 数据卷(Volumes) 挂载主机目录(Bind mounts) 数据卷 数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性: 数据卷可以在容器之间共享和重用 对数据卷的修改会立马生效 对数据卷的更新,不会影响镜像 数据卷默认会一直存在,即使容器被删除 注意: 数据卷的使用,类似于Linux下对目录或文件进行mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的数据卷。 Docker中提供了两种挂载方式,-v和-mount Docker新用户应该选择 --mount参数 经验丰富的Docker使用者对-v或者--volume已经很熟悉了,但是推荐使用-mount参数。 创建一个数据卷 docker volume create my-volume 查看指定数据卷的信息 docker volume inspect my-volume 启动一个挂载数据卷的容器: 在用docker run命令的时候,使用--mount标记来将数据卷挂载到容器里。 创建一个名为session-web的容器,并加载一个数据卷到容器中的/webapp目录。 # 方法一 docker run --name session-web -d -p 8888:8080 --mount source=my-volume,target=/webapp session-web:latest # 方法二 docker run --name session-web -d -p 8888:8080 -v my-volume:/webapp session-web:latest 删除数据卷 docker volume rm my-volume 数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用docker rm -v这个命令。 无主的数据卷可能会占据很多空间,要清理请使用以下命令 docker volume prune 挂载主机目录 使用--mount标记可以指定挂载一个本地主机的目录到容器中去 # 方法一 docker run --name session-web -d -p 8888:8080 \ -v my-volume:/webapp \ session-web:latest # 方法二 docker run --name session-web -d -p 8888:8080 \ --mount type=bind,source=/src/webapp,target=/opt/webapp session-web:latest 上面的命令加载主机的/src/webapp目录到容器的/opt/webapp目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。 本地目录的路径必须是绝对路径 以前,使用-v参数时如果本地目录不存在Docker会自动为你创建一个文件夹。 现在,使用--mount参数时如果本地目录不存在,Docker会报错。Docker挂载主机目录的默认权限是读写,用户也可以通过增加readonly指定为只读。 挂载一个本地主机文件作为数据卷 --mount标记也可以从主机挂载单个文件到容器中 # 方法一 docker run --rm -it \ --mount type=bind,source=#HOME/.bash_history,target=/root/.bash_history \ ubuntu:17.10 bash # 方法二 docker run --rm -it \ -v $HOME/.bash_history:/root/.bash_history \ ubuntu:17.10 bash

优秀的个人博客,低调大师

Spring Cloud Gateway 入门

文章首发于公众号《程序员果果》地址:https://mp.weixin.qq.com/s/wRwq99fNEW4gqgHvR9a-gQ 简介 Spring Cloud Gateway ,相比之前我们使用的 Zuul(1.x) 它有哪些优势呢?Zuul(1.x) 基于 Servlet,使用阻塞 API,它不支持任何长连接,如 WebSockets。Spring Cloud Gateway 使用非阻塞 API,支持 WebSockets,支持限流等新特性。本文首先用官方的案例带领大家来体验下Spring Cloud的一些简单的功能。 创建工程 创建工程springcloud工程,名为springcloud-gateway-hello pom.xml 内容如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.gf</groupId> <artifactId>springcloud-gateway-hello</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springcloud-gateway-hello</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project> 创建一个简单的路由 Spring Cloud Gateway 使用路由来处理对下游服务的请求。创建RouteLocator的Bean,在本案例将把所有请求路由到 http://httpbin.org。路由可以通过多种方式配置: @SpringBootApplication public class SpringcloudGatewayHelloApplication { public static void main(String[] args) { SpringApplication.run( SpringcloudGatewayHelloApplication.class, args ); } @Bean public RouteLocator myRoutes(RouteLocatorBuilder builder) { return builder.routes() .route(p -> p .path("/get") .filters(f -> f.addRequestHeader("Hello", "World")) .uri("http://httpbin.org:80")) .build(); } } 上述myRoutes方法RouteLocatorBuilder可以很容易地用于创建路由。除了创建路由之外,RouteLocatorBuilder还允许你在路由中添加各种 predicates(断言) 和 filters,以便根据特定条件更改请求和响应。 上面创建的route可以让请求“/get”请求都转发到“http://httpbin.org/get”。在route配置上,我们添加了一个filter,该filter会将请求添加一个header,key为hello,value为world。 启动项目,访问http://127.0.0.1:8080/get,显示如下: { "args": { }, "headers": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.9,zh-TW;q=0.8", "Cache-Control": "max-age=0", "Connection": "close", "Forwarded": "proto=http;host=\"127.0.0.1:8080\";for=\"127.0.0.1:55607\"", "Hello": "World", "Host": "httpbin.org", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", "X-Forwarded-Host": "127.0.0.1:8080" }, "origin": "127.0.0.1, 124.74.78.150", "url": "http://127.0.0.1:8080/get" } 可见当向gateway工程请求“/get”,gateway会将工程的请求转发到“http://httpbin.org/get”,并且在转发之前,加上一个filter,该filter会将请求添加一个header,key为hello,value为world。 使用Hystrix 在spring cloud gateway中可以使用Hystrix。Hystrix是 spring cloud中一个服务熔断降级的组件,在微服务系统有着十分重要的作用。Hystrix 在 spring cloud gateway中是以filter的形式使用的,代码如下: @Bean public RouteLocator myRoutes(RouteLocatorBuilder builder) { return builder.routes() .route(p -> p .path("/get") .filters(f -> f.addRequestHeader("Hello", "World")) .uri("http://httpbin.org:80")) .route(p -> p .host("*.hystrix.com") .filters(f -> f.hystrix(config -> config .setName("mycmd") .setFallbackUri("forward:/fallback"))) .uri("http://httpbin.org:80")) .build(); } 在上面的代码中,我们使用了另外一个router,该router使用host去断言请求是否进入该路由,当请求的host为 “*.hystrix.com”,都会进入该router,该router中有一个hystrix的filter,该filter可以配置名称、和指向性fallback的逻辑的地址,比如本案例中重定向到了“/fallback”。 现在写的一个“/fallback”的l逻辑: @RequestMapping("/fallback") public String fallback() { return "fallback"; } 使用curl执行以下命令: curl --dump-header - --header 'Host: www.hystrix.com' http://localhost:8080/delay/3 返回的响应为: HTTP/1.1 200 OK Content-Type: text/plain;charset=UTF-8 Content-Length: 8 fallback 可见,带host www.hystrix.com 的请求执行了hystrix的fallback的逻辑。 源码 https://github.com/gf-huanchupk/SpringCloudLearning/tree/master/chapter13/springcloud-gateway-hello

优秀的个人博客,低调大师

Prometheus入门+grafana集成

开始使用Prometheus $ systemctl start prometheus $ netstat -lntp tcp6 0 0 :::9090 :::* LISTEN 19824/./prometheus 在浏览器访问:http://ip:9090/graph 。Prometheus会把自身作为一个项目进行自监控,查看收集到监控项:http://172.16.180.129:9090/metrics (如果是首次启动,需要等待30s左右的时间) 使用内置表达式查看数据 地址:http://ip:9090/graph Prometheus内置监控项 prometheus_target_interval_length_seconds ,将该监控项直接输入console查询,可获取数据: ![image-20190322132500188](/Users/adai/Library/Application Support/typora-user-images/image-20190322132500188.png) 使用prometheus监控服务器 上面用Prometheus本身的数据简单演示了监控数据的查询,这里我们用一个监控服务器状态的例子来更加直观说明。 为监控服务器CPU、内存、磁盘、I/O等信息,首先需要安装node_exporter。node_exporter的作用是用于机器系统数据收集。 安装node_exporter node_exporter也是用Golang实现,直接使用预编译的二进制文件部署,开箱即用。 $ cd /home/prometheus && wget https://github.com/prometheus/node_exporter/releases/download/v0.17.0/node_exporter-0.17.0.linux-amd64.tar.gz $ tar zxvf node_exporter-0.17.0.linux-amd64.tar.gz $ mv node_exporter-0.17.0.linux-amd64 /usr/local/prometheus/node_exporter 创建systemd服务 $ vim /usr/lib/systemd/system/node_exporter.service [Unit] Description=node_exporter After=network.target [Service] Type=simple User=prometheus ExecStart=/usr/local/prometheus/node_exporter/node_exporter Restart=on-failure [Install] WantedBy=multi-user.target 启动node_exporter $ systemctl start node_exporter $netstat -lntp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp6 0 0 :::9100 :::* LISTEN 24126/node_exporter 修改prometheus.yml,加入下面的监控目标(node_exporter默认的抓取地址为http://ip:9100) - job_name: 'linux' static_configs: - targets: ['localhost:9100'] labels: instance: node1 说明:prometheus.yml中一共定义了两个监控,一个是监控prometheus自身服务,另一个是监控Linux服务器。 这里给一个完整示例: scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] - job_name: 'linux' static_configs: - targets: ['localhost:9100'] labels: instance: node1 重启prometheus服务 $ systemctl restart prometheus 在Prometheus Web查看监控的目标:访问Prometheus Web,在Status->Targets页面下,我们可以看到我们配置的两个Target(linux和prometheus),它们的State为UP。 查看memory使用情况 ![image-20190322134529082](/Users/adai/Library/Application Support/typora-user-images/image-20190322134529082.png) Prometheus Web界面自带的图表是非常基础的,比较适合用来做测试。如果要构建强大的Dashboard,还是需要更加专业的工具才行。接下来我们将使用Grafana来对Prometheus采集到的数据进行可视化展示。 prometheus集成grafana 在Grafana中添加Prometheus数据源:Configuration——DataSource——"add new DataSource"——Prometheus http URL:http://localhost:9090 access:server 上述配置完成后需要导入node-exporter-server-metrics 的数据模板到grafana,两种导入方法: 通过url导入:grafana——菜单栏加号➕——import—— 输入URL https://grafana.com/dashboards/405 —— 导入——Options (Name、Folder、Prometheus) —— import 下载后导入:grafana——菜单栏加号➕——import—— 输入 下载 好的json文件 ——import 完成上述操作后即可看到node-exporter采集的数据。 在Dashboards上选Node Exporter Server Metrics模板,就可以看到被监控服务器的CPU, 内存, 磁盘等统计信息。 在Dashboards上选Prometheus Status模板,查看Prometheus各项指标数据。

优秀的个人博客,低调大师

RocketMQ入门篇

RocketMQ整体结构 如上图所示,整体可以分成4个角色,分别是:Producer,Consumer,Broker以及NameServer; 1.NameServer 可以理解为是消息队列的协调者,Broker向它注册路由信息,同时Client向其获取路由信息,如果使用过Zookeeper,就比较容易理解了,但是功能比Zookeeper弱; NameServer本身是没有状态的,并且多个NameServer直接并没有通信,可以横向扩展多台,Broker会和每一台NameServer建立长连接; 2.Broker Broker是RocketMQ的核心,提供了消息的接收,存储,拉取等功能,一般都需要保证Broker的高可用,所以会配置Broker Slave,当Master挂掉之后,Consumer然后可以消费Slave; Broker分为Master和Slave,一个Master可以对应多个Slave,Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave; 3.Producer 消息队列的生产者,需要与NameServer建立连接,从NameServer获取Topic路由信息,并向提供Topic服务的Broker Master建立连接;Producer无状态,看集群部署; 4.Consumer 消息队列的消费者,同样与NameServer建立连接,从NameServer获取Topic路由信息,并向提供Topic服务的Broker Master,Slave建立连接; 5.Topic和Message Queue 在介绍完以上4个角色以后,还需要重点介绍一下上面提到的Topic和Message Queue;字面意思就是主题,用来区分不同类型的消息,发送和接收消息前都需要先创建Topic,针对Topic来发送和接收消息,为了提高性能和吞吐量,引入了Message Queue,一个Topic可以设置一个或多个Message Queue,有点类似kafka的分区(Partition),这样消息就可以并行往各个Message Queue发送消息,消费者也可以并行的从多个Message Queue读取消息; 单机配置和部署 以下部署在centos7,jdk1.8,rocketmq4.3.2;启动RocketMQ的顺序是先启动NameServer,然后再启动Broker; 1.NameServer启动 [root@localhost bin]# ./mqnamesrv Java HotSpot(TM) 64-Bit Server VM warning: Using the DefNew young collector with the CMS collector is deprecated and will likely be removed in a future release Java HotSpot(TM) 64-Bit Server VM warning: UseCMSCompactAtFullCollection is deprecated and will likely be removed in a future release. The Name Server boot success. serializeType=JSON 如上日志表示启动成功,默认端口为9876; 2.Broker启动 [root@localhost bin]# ./mqbroker Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000005c0000000, 8589934592, 0) failed; error='Cannot allocate memory' (errno=12) # # There is insufficient memory for the Java Runtime Environment to continue. # Native memory allocation (mmap) failed to map 8589934592 bytes for committing reserved memory. # An error report file with more information is saved as: # /root/rocketmq-all-4.3.2-bin-release/bin/hs_err_pid3977.log 启动失败,报内存不足,主要是rocketmq默认配置的启动参数值比较大,修改runbroker.sh即可 [root@localhost bin]# vi runbroker.sh JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g" 默认配置的可用内存为8g,虚拟机内存不够,修改为如下即可 JAVA_OPT="${JAVA_OPT} -server -Xms128m -Xmx128m -Xmn128m" 再次启动,日志如下,表示启动成功,默认端口为10911; [root@localhost bin]# ./mqbroker The broker[localhost.localdomain, 192.168.237.128:10911] boot success. serializeType=JSON 3.简单测试 3.1生产者 public class SyncProducer { public static void main(String[] args) throws Exception { // 构造Producer DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName"); producer.setNamesrvAddr("192.168.237.128:9876"); // 初始化Producer,整个应用生命周期内,只需要初始化1次 producer.start(); for (int i = 0; i < 100; i++) { Message msg = new Message("TopicTest", "TagA", ("Hello RocketMQ" + i).getBytes(RemotingHelper.DEFAULT_CHARSET)); SendResult sendResult = producer.send(msg); System.out.println(sendResult); } producer.shutdown(); } } 创建了一个DefaultMQProducer对象,同时设置了GroupName和NameServer地址,然后创建Message消息通过DefaultMQProducer将消息发送出去,返回一个SendResult对象; 3.2消费者 public class PushConsumer { public static void main(String[] args) throws MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please rename to unique group name"); consumer.setNamesrvAddr("192.168.237.128:9876"); consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); consumer.subscribe("TopicTest", "*"); consumer.registerMessageListener(new MessageListenerConcurrently() { public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { System.out.printf(Thread.currentThread().getName() + "Receive New Messages :" + msgs + "%n"); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } }); consumer.start(); } } 同样指定了GroupName和NameServer地址,订阅了Topic; 3.3运行测试 直接运行生产者报如下错误: Exception in thread "main" org.apache.rocketmq.client.exception.MQClientException: No route info of this topic, TopicTest See http://rocketmq.apache.org/docs/faq/ for further details. at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:634) at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1253) at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1203) at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:214) at com.rocketmq.SyncProducer.main(SyncProducer.java:26) 错误显示"没有此Topic的路由信息",也就是生产者在发送消息的时候没有获取到路由信息,找不到指定的Broker,可能的原因: 1.Broker没有正确连接NameServer 2.Producer没有连接NameServer 3.Topic没有被正确创建 SyncProducer中指定了NameServer的地址,同时RocketMQ默认情况下会自动创建Topic,所以原因是Broker没有注册到NameServer,重新指定NameServer再启动: [root@localhost bin]# ./mqbroker -n localhost:9876 The broker[localhost.localdomain, 192.168.237.128:10911] boot success. serializeType=JSON and name server is localhost:9876 再次运行SyncProducer,日志如下: SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C4C60000, offsetMsgId=C0A8ED8000002A9F000000000000229C, messageQueue=MessageQueue[topic=TopicTest, brokerName=localhost.localdomain, queueId=1], queueOffset=11] SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C4CD0001, offsetMsgId=C0A8ED8000002A9F000000000000234D, messageQueue=MessageQueue [topic=TopicTest, brokerName=localhost.localdomain, queueId=2], queueOffset=9] SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C4D90002, offsetMsgId=C0A8ED8000002A9F00000000000023FE, messageQueue=MessageQueue[topic=TopicTest, brokerName=localhost.localdomain, queueId=3], queueOffset=9] SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C4E80003, offsetMsgId=C0A8ED8000002A9F00000000000024AF, messageQueue=MessageQueue [topic=TopicTest, brokerName=localhost.localdomain, queueId=0], queueOffset=11] SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C4F40004, offsetMsgId=C0A8ED8000002A9F0000000000002560, messageQueue=MessageQueue [topic=TopicTest, brokerName=localhost.localdomain, queueId=1], queueOffset=12] SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C4F70005, offsetMsgId=C0A8ED8000002A9F0000000000002611, messageQueue=MessageQueue [topic=TopicTest, brokerName=localhost.localdomain, queueId=2], queueOffset=10] SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C5030006, offsetMsgId=C0A8ED8000002A9F00000000000026C2, messageQueue=MessageQueue [topic=TopicTest, brokerName=localhost.localdomain, queueId=3], queueOffset=10] SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C5070007, offsetMsgId=C0A8ED8000002A9F0000000000002773, messageQueue=MessageQueue [topic=TopicTest, brokerName=localhost.localdomain, queueId=0], queueOffset=12] SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C50A0008, offsetMsgId=C0A8ED8000002A9F0000000000002824, messageQueue=MessageQueue [topic=TopicTest, brokerName=localhost.localdomain, queueId=1], queueOffset=13] SendResult [sendStatus=SEND_OK, msgId=0A0D53073B6073D16E933086C50D0009, offsetMsgId=C0A8ED8000002A9F00000000000028D5, messageQueue=MessageQueue [topic=TopicTest, brokerName=localhost.localdomain, queueId=2], queueOffset=11] 消费者使用的是push模式,可以实时接受消息: ConsumeMessageThread_13Receive New Messages :[MessageExt [queueId=1, storeSize=177,queueOffset=11, sysFlag=0, bornTimestamp=1547086138566, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430770, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F000000000000229C, commitLogOffset=8860, bodyCRC=705268097, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=12, CONSUME_START_TIME=1547086138573, UNIQ_KEY=0A0D53073B6073D16E933086C4C60000, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 48], transactionId='null'}]] ConsumeMessageThread_3Receive New Messages :[MessageExt [queueId=2, storeSize=177, queueOffset=9, sysFlag=0, bornTimestamp=1547086138573, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430783, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F000000000000234D, commitLogOffset=9037, bodyCRC=1561245975, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=10, CONSUME_START_TIME=1547086138598, UNIQ_KEY=0A0D53073B6073D16E933086C4CD0001, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 49], transactionId='null'}]] ConsumeMessageThread_17Receive New Messages :[MessageExt [queueId=3, storeSize=177, queueOffset=9, sysFlag=0, bornTimestamp=1547086138585, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430794, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F00000000000023FE, commitLogOffset=9214, bodyCRC=1141369005, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=10, CONSUME_START_TIME=1547086138601, UNIQ_KEY=0A0D53073B6073D16E933086C4D90002, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 50], transactionId='null'}]] ConsumeMessageThread_9Receive New Messages :[MessageExt [queueId=0, storeSize=177, queueOffset=11, sysFlag=0, bornTimestamp=1547086138600, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430807, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F00000000000024AF, commitLogOffset=9391, bodyCRC=855693371, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=12, CONSUME_START_TIME=1547086138612, UNIQ_KEY=0A0D53073B6073D16E933086C4E80003, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 51], transactionId='null'}]] ConsumeMessageThread_15Receive New Messages :[MessageExt [queueId=1, storeSize=177, queueOffset=12, sysFlag=0, bornTimestamp=1547086138612, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430809, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F0000000000002560, commitLogOffset=9568, bodyCRC=761548184, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=13, CONSUME_START_TIME=1547086138626, UNIQ_KEY=0A0D53073B6073D16E933086C4F40004, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 52], transactionId='null'}]] ConsumeMessageThread_11Receive New Messages :[MessageExt [queueId=2, storeSize=177, queueOffset=10, sysFlag=0, bornTimestamp=1547086138615, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430820, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F0000000000002611, commitLogOffset=9745, bodyCRC=1516469518, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=11, CONSUME_START_TIME=1547086138628, UNIQ_KEY=0A0D53073B6073D16E933086C4F70005, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 53], transactionId='null'}]] ConsumeMessageThread_4Receive New Messages :[MessageExt [queueId=3, storeSize=177,queueOffset=10, sysFlag=0, bornTimestamp=1547086138627, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430824, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F00000000000026C2,commitLogOffset=9922, bodyCRC=1131031732,reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=11, CONSUME_START_TIME=1547086138633, UNIQ_KEY=0A0D53073B6073D16E933086C5030006, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 54], transactionId='null'}]] ConsumeMessageThread_14Receive New Messages :[MessageExt [queueId=0, storeSize=177, queueOffset=12, sysFlag=0, bornTimestamp=1547086138631, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430827, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F0000000000002773, commitLogOffset=10099, bodyCRC=879565858, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=13, CONSUME_START_TIME=1547086138635, UNIQ_KEY=0A0D53073B6073D16E933086C5070007, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 55], transactionId='null'}]] ConsumeMessageThread_10Receive New Messages :[MessageExt [queueId=1, storeSize=177, queueOffset=13, sysFlag=0, bornTimestamp=1547086138634, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430830, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F0000000000002824, commitLogOffset=10276, bodyCRC=617742771, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=14, CONSUME_START_TIME=1547086138638, UNIQ_KEY=0A0D53073B6073D16E933086C50A0008, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 56], transactionId='null'}]] ConsumeMessageThread_7Receive New Messages :[MessageExt [queueId=2, storeSize=177, queueOffset=11, sysFlag=0, bornTimestamp=1547086138637, bornHost=/192.168.237.1:53524, storeTimestamp=1547139430833, storeHost=/192.168.237.128:10911, msgId=C0A8ED8000002A9F00000000000028D5, commitLogOffset=10453, bodyCRC=1406480677, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=12, CONSUME_START_TIME=1547086138641, UNIQ_KEY=0A0D53073B6073D16E933086C50D0009, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 57], transactionId='null'}]] 多机集群配置和部署 分别部署两台NameServer,两台Broker并且分别提供Slave,准备两台电脑分别是本机的windows以及虚拟机centos; 1.启动NameServer 分别启动2台NameServer,端口号都使用默认的9876,地址端口如下: 192.168.237.128:9876 10.13.83.7:9876 2.启动Broker 每台机器上分别启动一个Master和一个Slave,互为主备,在主目录下的conf文件夹下提供了多种broker配置模式,分别有:2m-2s-async,2m-2s-sync,2m-noslave,可以以此为模版做如下配置: 2.1配置10.13.83.7Master和Slave Master配置如下: namesrvAddr=192.168.237.128:9876;10.13.83.7:9876 brokerClusterName=DefaultCluster brokerName=broker-a brokerId=0 deleteWhen=04 fileReservedTime=48 brokerRole=SYNC_MASTER flushDiskType=ASYNC_FLUSH listenPort=10911 storePathRootDir=E:/rocketmq-all-4.3.2-bin-release/store-a-m Slave配置如下: namesrvAddr=192.168.237.128:9876;10.13.83.7:9876 brokerClusterName=DefaultCluster brokerName=broker-a brokerId=1 deleteWhen=04 fileReservedTime=48 brokerRole=SLAVE flushDiskType=ASYNC_FLUSH listenPort=10811 storePathRootDir=E:/rocketmq-all-4.3.2-bin-release/store-a-s 分别启动结果如下: E:\rocketmq-all-4.3.2-bin-release\bin>mqbroker -c E:\rocketmq-all-4.3.2-bin-rele ase\conf\broker-m.conf The broker[broker-a, 10.13.83.7:10911] boot success. serializeType=JSON and name server is 192.168.237.128:9876;10.13.83.7:9876 以上是Master启动日志,Slave日志如下: E:\rocketmq-all-4.3.2-bin-release\bin>mqbroker -c E:\rocketmq-all-4.3.2-bin-rele ase\conf\broker-s.conf The broker[broker-a, 10.13.83.7:10811] boot success. serializeType=JSON and name server is 192.168.237.128:9876;10.13.83.7:9876 2.2配置10.13.83.7Slave Master配置如下: namesrvAddr=192.168.237.128:9876;10.13.83.7:9876 brokerClusterName=DefaultCluster brokerName=broker-b brokerId=0 deleteWhen=04 fileReservedTime=48 brokerRole=SYNC_MASTER flushDiskType=ASYNC_FLUSH listenPort=10911 storePathRootDir=/root/rocketmq-all-4.3.2-bin-release/store-b-m Slave配置如下: namesrvAddr=192.168.237.128:9876;10.13.83.7:9876 brokerClusterName=DefaultCluster brokerName=broker-b brokerId=1 deleteWhen=04 fileReservedTime=48 brokerRole=SLAVE flushDiskType=ASYNC_FLUSH listenPort=10811 storePathRootDir=/root/rocketmq-all-4.3.2-bin-release/store-b-s 启动日志分别如下: [root@localhost bin]# ./mqbroker -c ../conf/broker-m.conf The broker[broker-b, 192.168.237.128:10911] boot success. serializeType=JSON and name server is 192.168.237.128:9876;10.13.83.7:9876 [root@localhost bin]# ./mqbroker -c ../conf/broker-s.conf The broker[broker-b, 192.168.237.128:10811] boot success. serializeType=JSON and name server is 192.168.237.128:9876;10.13.83.7:9876 3.配置说明 1.namesrvAddr NameServer地址,可以配置多个,用逗号分隔; 2.brokerClusterName 所属集群名称,如果节点较多可以配置多个 3.brokerName broker名称,master和slave使用相同的名称,表明他们的主从关系 4.brokerId 0表示Master,大于0表示不同的slave 5.deleteWhen 表示几点做消息删除动作,默认是凌晨4点 6.fileReservedTime 在磁盘上保留消息的时长,单位是小时 7.brokerRole 有三个值:SYNC_MASTER,ASYNC_MASTER,SLAVE;同步和异步表示Master和Slave之间同步数据的机制; 8.flushDiskType 刷盘策略,取值为:ASYNC_FLUSH,SYNC_FLUSH表示同步刷盘和异步刷盘;SYNC_FLUSH消息写入磁盘后才返回成功状态,ASYNC_FLUSH不需要; 9.listenPort 启动监听的端口号 10.storePathRootDir 存储消息的根目录 管理工具 1.命令行管理工具 mqadmin是RocketMQ自带的命令行管理工具,可以创建、修改Topic,查询消息,更新配置信息等操作,具体可以通过如下命令查看: E:\rocketmq-all-4.3.2-bin-release\bin>mqadmin The most commonly used mqadmin commands are: updateTopic Update or create topic deleteTopic Delete topic from broker and NameServer. updateSubGroup Update or create subscription group deleteSubGroup Delete subscription group from broker. updateBrokerConfig Update broker's config updateTopicPerm Update topic perm topicRoute Examine topic route info topicStatus Examine topic Status info topicClusterList get cluster info for topic brokerStatus Fetch broker runtime status data queryMsgById Query Message by Id queryMsgByKey Query Message by Key queryMsgByUniqueKey Query Message by Unique key queryMsgByOffset Query Message by offset printMsg Print Message Detail printMsgByQueue Print Message Detail sendMsgStatus send msg to broker. brokerConsumeStats Fetch broker consume stats data producerConnection Query producer's socket connection and client vers consumerConnection Query consumer's socket connection, client version ubscription consumerProgress Query consumers's progress, speed consumerStatus Query consumer's internal data structure cloneGroupOffset clone offset from other group. clusterList List all of clusters topicList Fetch all topic list from name server updateKvConfig Create or update KV config. deleteKvConfig Delete KV config. wipeWritePerm Wipe write perm of broker in all name server resetOffsetByTime Reset consumer offset by timestamp(without client t). updateOrderConf Create or update or delete order conf cleanExpiredCQ Clean expired ConsumeQueue on broker. cleanUnusedTopic Clean unused topic on broker. startMonitoring Start Monitoring statsAll Topic and Consumer tps stats allocateMQ Allocate MQ checkMsgSendRT check message send response time clusterRT List All clusters Message Send RT getNamesrvConfig Get configs of name server. updateNamesrvConfig Update configs of name server. getBrokerConfig Get broker config by cluster or special broker! queryCq Query cq command. sendMessage Send a message consumeMessage Consume message See 'mqadmin help <command>' for more information on a specific command. 列出了所有支持的命令以及简单的介绍,如果想看详细的可以如下命令: E:\rocketmq-all-4.3.2-bin-release\bin>mqadmin help statsAll usage: mqadmin statsAll [-a] [-h] [-n <arg>] [-t <arg>] -a,--activeTopic print active topic only -h,--help Print help -n,--namesrvAddr <arg> Name server address list, eg: 192.168.0.1:9876;192.168 .0.2:9876 -t,--topic <arg> print select topic only 2.图形界面管理工具 除了命令,还提供了图形界面管理工具,在RocketMQ的扩展包里面,具体地址如下: https://github.com/apache/rocketmq-externals/tree/release-rocketmq-console-1.0.0/rocketmq-console 目前的稳定版本是1.0.0,可以下载下来在本地运行,对application.properties做简单配置: rocketmq.config.namesrvAddr=10.13.83.7:9876 需要指定NameServer的地址,然后就可以打包运行了,运作之后会启动8080端口,直接访问地址: http://localhost:8080 总结 本文从最简单的安装部署入手,并对常用的配置参数做了简单介绍;然后了解了RocketMQ的部署的整体结构,分别对其中的角色做了简单介绍;最后介绍了两种RocketMQ的管理工具,方便对RocketMQ的监控和管理。

优秀的个人博客,低调大师

Maven入门教程

GitHub仓库:Fundebug/maven-tutorial Maven简介 Maven是Java项目构建工具,可以用于管理Java依赖,还可以用于编译、打包以及发布Java项目,类似于JavaScript生态系统中的NPM。 Maven的命令行工具为mvn,其常用命令如下表所示: | 命令 | 说明 | | ----------- | -----------------------| | mvn compile | 编译Java源代码 | | mvn package | 打包Java项目 || mvn deploy | 将Java项目发布到Maven仓库 || mvn clean | 删除构建目录 | Maven的配置文件为pom.xml,这个文件有个很吓人的学术名字Project Object Model,但是怎么看它都只是个普通的配置文件,与NPM中的package.json没啥本质区别。 Maven的中央仓库为Maven Repository,这里可以找到各种Java依赖,例如我们Fundebug的异常监控插件fundebug-java与fundebug-spring。 安装Maven 在MacBook上使用brew安装很方便 brew install maven 我安装的是maven版本3.5.4 mvn -version Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-18T02:33:14+08:00) Maven home: /usr/local/Cellar/maven/3.5.4/libexec Java version: 1.8.0_192, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre Default locale: zh_CN, platform encoding: UTF-8 OS name: "mac os x", version: "10.14.2", arch: "x86_64", family: "mac" 示例代码 本文示例代码都在GitHub仓库Fundebug/maven-tutorial。 使用tree命令可以查看项目的目录结构: tree -v . ├── pom.xml └── src └── main └── java └── com └── fundebug └── Hello.java pom.xml为Maven配置文件,位于项目的根目录。 Hello.java为Java源代码,位于src/main/java/com/fundebug目录中。根据Maven对目录结构的要求,Java源代码必须位于src/main/java目录。 Hello.java package com.fundebug; import org.json.JSONObject; public class Hello { public static void main(String[] args) { JSONObject tomJsonObj = new JSONObject(); tomJsonObj.put("name", "Fundebug"); tomJsonObj.put("url", "https://www.fundebug.com"); System.out.println(tomJsonObj.toString(4)); } } Hello.java非常简单,定义了一个JSON对象,然后把它打印出来了。 package定义的包名为com.fundebug,需要与所在的目录结构相吻合,因此Hello.java位于src/main/java/com/fundebug目录中,而不是src/main/java/目录中。 代码依赖于第三方模块json,因此需要在pom.xml配置dependency: <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20180813</version> </dependency> pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- 坐标 --> <groupId>com.fundebug</groupId> <artifactId>hello</artifactId> <version>1.0</version> <!-- 依赖 --> <dependencies> <!-- https://mvnrepository.com/artifact/org.json/json --> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20180813</version> </dependency> </dependencies> </project> pom.xml中,<project></project>为最外层的标签;<modelVersion>4.0.0</modelVersion>定义了所使用的POM版本。这2个标签基本上是不变的。 groupId、artifactId与version一起则定义了模块的坐标(Coordinates),每个公共模块的坐标应该是唯一的: groupId:组织名称,通常是把域名反过来,例如com.fundebug artifactId:模块名称,例如fundebug-java version:模块版本,例如0.2.0 <dependencies></dependencies>定义了当前项目所依赖的模块: <dependencies> <!-- https://mvnrepository.com/artifact/org.json/json --> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20180813</version> </dependency> </dependencies> Maven可以根据<dependency></dependency>中定义的坐标,自动下载所依赖的模块。在MacBook上,Maven将下载的模块缓存在$HOME/.m2/目录。 使用mvn打包 执行mvn package命令,即可将源码打包为.jar文件: mvn package [INFO] Scanning for projects... [INFO] [INFO] -------------------------< com.fundebug:hello >------------------------- [INFO] Building hello 1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /Users/fundebug/Desktop/maven-tutorial/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello --- [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent! [INFO] Compiling 1 source file to /Users/fundebug/Desktop/maven-tutorial/target/classes [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /Users/fundebug/Desktop/maven-tutorial/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello --- [INFO] No sources to compile [INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello --- [INFO] No tests to run. [INFO] [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello --- [INFO] Building jar: /Users/fundebug/Desktop/maven-tutorial/target/hello-1.0.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.789 s [INFO] Finished at: 2019-01-05T15:23:02+08:00 [INFO] ------------------------------------------------------------------------ mvn package执行之后,项目中会新增一个tartget目录,编译的字节码文件位于target/classes目录,而jar包位于target/hello-1.0.jar: tree -v . ├── pom.xml ├── src │ └── main │ └── java │ └── com │ └── fundebug │ └── Hello.java └── target ├── classes │ └── com │ └── fundebug │ └── Hello.class ├── hello-1.0.jar 使用mvn运行 打包好的jar包,可以直接使用java命令运行时,注意需要指定所依赖的jar包。对于所依赖的jar包,Maven则会自动下载依赖,放在本地仓库中。在MacBook上,Maven本地仓库位于$HOME/.m2/目录。 java -cp target/hello-1.0.jar:$HOME/.m2/repository/org/json/json/20180813/json-20180813.jar com.fundebug.Hello { "name": "Fundebug", "url": "https://www.fundebug.com" } 也可以使用mvn exec:java命令执行,不需要指定依赖的jar包,更加方便: mvn exec:java -Dexec.mainClass="com.fundebug.Hello" [INFO] Scanning for projects... [INFO] [INFO] -------------------------< com.fundebug:hello >------------------------- [INFO] Building hello 1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ hello --- { "name": "Fundebug", "url": "https://www.fundebug.com" } [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.837 s [INFO] Finished at: 2019-01-05T15:33:57+08:00 [INFO] ------------------------------------------------------------------------ 参考 Simple Maven Project Maven Dependency Management Java JSON Tutorial and Example: JSON-Java (org.json)

优秀的个人博客,低调大师

Kubernetes Helm入门指南

什么是Helm?这可不是暗黑破坏神里装备的名称:头盔,而是Kubernetes的一个包管理工具,用来简化Kubernetes应用的部署和管理。我们Helm和Kubernetes的关系,我们可以理解成yum和CentOS,apt-get和Ubuntu的关系。 Helm由两部分组成,客户端helm和服务端tiller。 其中tiller运行在Kubernetes集群上,管理chart,而客户端helm就是一个命令行工具,可在本地运行,一般运行在持续集成/持续交付的服务器上 。 下图是helm的架构图。 我们现在就来试用下helm。 首先安装helm客户端。 下载helm执行文件的压缩包: wget -O helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.11.0-l

优秀的个人博客,低调大师

Java入门—多线程

线程是比进程还要小的运行单位,一个进程包含多个线程。 什么是多线程 线程的创建 两种方式: 创建一个Thread类,或者一个Thread子类的对象 创建一个实现Runnable接口的类的对象 Thread类: Thread是一个线程类,位于java.lang包下 image.png Thread类的常用方法 image.png Runnable接口 只有一个方法run() Runnable是java中用以实现线程的接口 任何实现线程功能的类都必须实现该接口 继承Thread类的方式创建线程类,重写run方法: package com.imooc.thread; class MyThread extends Thread{ public void run(){ System.out.println(getName()+"该线程正在执行!"); } } public class ThreadTest{ public static void main(String[] args){ System.out.println("主线程1"); MyThread mt = new MyThread(); mt.start(); System.out.println("主线程2"); } } Runnable创建线程: 为什么要实现Runnable接口? 因为: Java不支持多继承 当你不打算重写Thread类的其他方法 package com.imooc.thread; class PrintRunnable implements Runnable{ @Override public void run() { int i = 1; while (i<=5){ System.out.println(Thread.currentThread().getName()+"正在运行"); i++; } } } public class ThreadTest{ public static void main(String[] args){ PrintRunnable pr = new PrintRunnable(); Thread t1 = new Thread(pr); t1.start(); Thread t2 = new Thread(pr); t2.start(); } } 线程的状态和生命周期 线程的状态 新建 可运行 正在运行 阻塞 终止 线程的生命周期 image.png sleep方法:在指定的毫秒数内,让线程休眠。(暂停执行) public static void sleep(long millis) 参数单位:毫秒 示例: class MyThread implements Runnable{ @Override public void run() { for(int i = 0; i<10;i++){ System.out.println(Thread.currentThread().getName()+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Test { public static void main(String[] args){ MyThread m = new MyThread(); Thread t = new Thread(m); t.start(); } } 调用sleep时需要捕获异常。 join()方法:优先执行线程。(抢占资源) public final void join() join方法的参数为毫秒,代表:超过此时间交出资源使用权。 示例: class MyThread implements Runnable{ @Override public void run() { for(int i = 0; i<10;i++){ System.out.println(Thread.currentThread().getName()+i); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Test { public static void main(String[] args){ MyThread m = new MyThread(); Thread t = new Thread(m); t.start(); try { t.join(1000); } catch (InterruptedException e) { e.printStackTrace(); } for(int j = 0; j<10;j++){ System.out.println("主线程"); } } } 线程的调度 线程优先级 Java为线程类提供了10个优先级 优先级可以用整数1-10表示,超出范围会抛出异常 主线程默认优先级为5 优先级常量 MAX_PRIORITY : 最高优先级(10) MIN_PRIORITY : 最低优先级(1) NORM_PRIORITY :默认优先级(5) image.png 测试代码: class MyThread implements Runnable{ private String name; public MyThread(String name){ this.name = name; } @Override public void run() { for(int i = 0; i<10;i++){ System.out.println(Thread.currentThread().getName()+i+name); } } } public class Test { public static void main(String[] args){ int i = Thread.currentThread().getPriority(); MyThread m = new MyThread("Allen"); Thread t = new Thread(m); MyThread m1 = new MyThread("ming"); Thread t1 = new Thread(m1); t.setPriority(Thread.MAX_PRIORITY); t1.setPriority(Thread.MIN_PRIORITY); int y = t.getPriority(); int y1 = t1.getPriority(); System.out.println("Allen线程优先级"+y); System.out.println("ming线程优先级"+y1); t.start(); t1.start(); } } 线程同步 多线程运行时的问题: 各个线程是通过竞争CPU时间而获得运行机会的 各个线程什么时候得到CPU时间、占用多久,是不可预测的 一个正在运行着的线程在什么地方被暂停是不确定的 使用synchronized关键字加锁。同一时刻只能单个操作。 synchronized关键字可以用在:成员方法、静态方法、语句块 public synchronized void F(){} public static synchronized void F(){} synchronized (){} 线程间通信 Java中的线程通信和Python中的差不多,通过中间队列类存储,由消费者和生产者负责放入和取出。 image.png wait方法:中断方法的执行,使线程等待 notify方法:唤醒处于等待的某一个线程 notifyAll方法:唤醒处于等待的全部线程 小结 创建线程的两种方式: 继承Thread类创建线程 new Thread().start() 实现Runnable接口创建线程 new Thread(new MyRunable()).start() 线程的5种状态: 新建 可运行 运行 阻塞 终止 sleep、join、wait、notify、notifyAll方法: 线程优先级: 最高、最低。 获取优先级、设置优先级。 先启动的线程尽管优先级低,也会可能先执行。 线程同步: synchronized关键字,可以用在:成员方法、静态方法、语句块。 上述文章如有帮助记得点赞呦,关注后第一时间获得最新笔记,持续更新~

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册