首页 文章 精选 留言 我的

精选列表

搜索[高并发],共10000篇文章
优秀的个人博客,低调大师

Java并发编程专题系列之从源码分析Mutex锁的运行原理

并行编程之条件变量(posix condition variables) 在整理Java LockSupport.park()的东东,看到了个"Spurious wakeup",重新梳理下。 #include <pthread.h> struct msg { struct msg *m_next; /* ... more stuff here ... */ }; struct msg *workq; pthread_cond_t qready = PTHREAD_COND_INITIALIZER; pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER; void process_msg(void) { struct msg *mp; for (;;) { pthread_mutex_lock(&qlock); while (workq == NULL) pthread_cond_wait(&qready, &qlock); mp = workq; workq = mp->m_next; pthread_mutex_unlock(&qlock); /* now process the message mp */ } } void enqueue_msg(struct msg *mp) { pthread_mutex_lock(&qlock); mp->m_next = workq; workq = mp; pthread_mutex_unlock(&qlock); pthread_cond_signal(&qready); } 一个简单的消息生产者和消费者的代码,它们之间用condition同步。 这个代码最容易让人搞混的是process_msg函数里的pthread_mutex_lock 和pthread_mutex_unlock 是一对函数调用,前面加锁,后面解锁。的确,是加锁解锁,但是它们两不是一对的。它们的另一半在pthread_cond_wait函数里。 pthread_cond_wait函数可以认为它做了三件事: 把自身线程放到condition的等待队列里,把mutex解锁; 等待被唤醒(当其它线程调用pthread_cond_signal或者pthread_cond_broadcast时); 被唤醒之后,对mutex加锁,再返回。 mutex和condition实际上是绑定在一起的,一个condition只能对应一个mutex。 在Java的代码里,Condition对象只能通过lock.newCondition()的函数来获取。 Spurious wakeup 所谓的spurious wakeup,指的是一个线程调用pthread_cond_signal(),却有可能不止一个线程被唤醒。 假定有三个线程,线程A正在执行pthread_cond_wait,线程B正在执行pthread_cond_signal,线程C正准备执行pthread_cond_wait函数。 pthread_cond_wait(mutex, cond): value = cond->value; /* 1 */ pthread_mutex_unlock(mutex); /* 2 */ pthread_mutex_lock(cond->mutex); /* 10 */ if (value == cond->value) { /* 11 */ me->next_cond = cond->waiter; cond->waiter = me; pthread_mutex_unlock(cond->mutex); unable_to_run(me); } else pthread_mutex_unlock(cond->mutex); /* 12 */ pthread_mutex_lock(mutex); /* 13 */ pthread_cond_signal(cond): pthread_mutex_lock(cond->mutex); /* 3 */ cond->value++; /* 4 */ if (cond->waiter) { /* 5 */ sleeper = cond->waiter; /* 6 */ cond->waiter = sleeper->next_cond; /* 7 */ able_to_run(sleeper); /* 8 */ } pthread_mutex_unlock(cond->mutex); /* 9 */ 线程A执行了第1,2步,这时它释放了mutex,然后线程B拿到了这个mutext,并且pthread_cond_signal函数时执行并返回了。 于是线程B就是一个所谓的“spurious wakeup”。 /build/buildd/eglibc-2.19/nptl/pthread_cond_wait.c /build/buildd/eglibc-2.19/nptl/pthread_cond_signal.c wait morphing优化 从而会有一个叫“wait morphing”优化,就是如果线程被唤醒但是不能获取到mutex,则线程被转移(morphing)到mutex的等待队列里。 The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() orpthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked bythe thread calling pthread_cond_broadcast() or pthread_cond_signal(). 是先调用pthread_mutex_unlock,再调用pthread_cond_signal。 void enqueue_msg(struct msg *mp) { pthread_mutex_lock(&qlock); mp->m_next = workq; workq = mp; pthread_mutex_unlock(&qlock); pthread_cond_signal(&qready); } 有的地方给出的是先调用pthread_cond_signal,再调用pthread_mutex_unlock: void enqueue_msg(struct msg *mp) { pthread_mutex_lock(&qlock); mp->m_next = workq; workq = mp; pthread_cond_signal(&qready); pthread_mutex_unlock(&qlock); } 先unlock再signal,这有个好处,就是调用enqueue_msg的线程可以再次参与mutex的竞争中,这样意味着可以连续放入多个消息,这个可能会提高效率。类似Java里ReentrantLock的非公平模式。 先signal再unlock,有可能会出现一种情况是被signal唤醒的线程会因为不能马上拿到mutex(还没被释放),从而会再次休眠,这样影响了效率。 可见在调用signal之前,可以不持有mutex,除非是“predictable scheduling”,可预测的调度行为。这种可能是实时系统才有这种严格的要求。 为什么要用while循环来判断条件是否成立? while (workq == NULL) pthread_cond_wait(&qready, &qlock); 而不用if来判断? if (workq == NULL) pthread_cond_wait(&qready, &qlock); 一个原因是spurious wakeup,但即使没有spurious wakeup,也是要用While来判断的。 线程A,线程B在pthread_cond_wait函数中等待,然后线程C把消息放到队列里,再调用pthread_cond_broadcast,然后线程A先获取到mutex,处理完消息完后,这时workq就变成NULL了。 线程B才获取到mutex,那么这时实际上是没有资源供线程B使用的。所以从pthread_cond_wait函数返回之后,还是要判断条件是否成功,如果成立,再进行处理。 pthread_cond_signal和pthread_cond_broadcast 认为调用pthread_cond_broadcast来唤醒所有的线程是比较好的写法。 但是我认为pthread_cond_signal和pthread_cond_broadcast是两个不同东东,不能简单合并在同一个函数调用。 只唤醒一个效率和唤醒全部等待线程的效率显然不能等同。典型的condition是用CLH或者MCS来实现的,要通知所有的线程,则要历遍链表,显然效率降低。 mutex,condition是不是公平(fair)的? #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; volatile int mutexCount = 0; void mutexFairTest(){ int localCount = 0; while(1){ pthread_mutex_lock(&lock); __sync_fetch_and_add(&mutexCount, 1); localCount += 1; if(mutexCount > 100000000){ break; } pthread_mutex_unlock(&lock); } pthread_mutex_unlock(&lock); printf("localCount:%d\n", localCount); } int main() { pthread_mutex_lock(&lock); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_mutex_unlock(&lock); sleep(100); } 输出结果是: localCount:16930422 localCount:16525616 localCount:16850294 localCount:16129844 localCount:17329693 localCount:16234137 连续调用pthread_cond_signal,会唤醒多少次/多少个线程? 比如线程a,b 在调用pthread_cond_wait之后等待,然后线程c, d同时调用pthread_cond_signal,那么a, b线程是否都能被唤醒? 会不会出现c, d, a 这种调用顺序,然后b一直在等待,然后死锁了? The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond). 因此,如果有线程已经在调用pthread_cond_wait等待的情况下,pthread_cond_signal调用至少会唤醒等待中的一个线程。 所以不会出现上面的线程b一直等待的情况。

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

如何最大化调优单台服务器的并发能力?

如下图片详细的描述了单台服务器的硬件配置和Nginx配置、Tomcat配置,以及文件句柄数信息。 1.以目前的情况如何再次把服务器整体性能优化到最优? 2.目前文件句柄数修改之后,设置不上,各种方法都试过了。 Nginx配置参数 Nginx分发Tomcat配置 Tomcat目前的配置参数 CPU信息 文件句柄数信息 修改文件句柄数,但是修改不了 系统运行时情况

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

Linux Lab 发布 v0.3,简化操作接口并发布首份中文手册

Linux Lab是一套用于 Linux 内核学习、开发和测试的即时实验室,可以极速搭建和使用,功能强大,用法简单! 可以用它来高效地学习处理器架构、Linux 内核、嵌入式 Linux 系统、C 语言编程、Linux 汇编、Shell 编程等。 Linux Lab Boot example 已经跃跃欲试了?!快来看看: Linux Lab v0.3 中文手册 Linux Lab v0.3 英文手册 Linux Lab:难以抗拒的十大理由 如果您想学习 Linux 0.11 内核和 Linux X86 汇编语言,也可以访问另外两套 Lab,即Linux 0.11 Lab和CS630 Qemu Lab。 版本更新 Linux Lab 先后于 6 月 29 日和 10 月 30 日发布了v0.1和v0.2正式版。 在过去数个月内,Linux Lab 连续发布了 v0.3 的 3 个候选版本,本次发布v0.3 正式版。 本次 v0.3-rc3 ~ v0.3 之间有 119 笔变更,整个 v0.2 ~ v0.3 之间有 366 笔变更,期间有多位贡献者提交了 Pull Request,参与了项目测试和试用,并提出了改进建议,非常感谢大家的参与和贡献: $ git log --format='%aN' v0.2..HEAD | sort -u LastRitter unicornx Wu Zhangjin $ git log --oneline v0.2..HEAD | wc -l 366 本次主要更新如下: 统一了所有组件的公共操作接口更方便记忆 新增了make cmd [kernel|uboot|root|qemu] [option=value]操作方式 例如:make defconfig kernel等同于make kernel-defconfig 更多命令包括 download, checkout, patch, defconfig, menuconfig, build, boot, test, debug 进一步优化了大型仓库的下载体验 通过git init + fetch取代git clone 通过添加自动依赖关系简化了命令执行并大幅度提升实验效率 make boot build=kernel一条命令完成下载,检出版本,配置,编译,启动全过程 为多本知名 Linux 图书新增了 v2.6.10, v2.6.11, v2.6.12, v2.6.14, v2.6.21, v2.6.24 等多个历史版本内核 闲置在家的经典 Linux 图书不妨翻出来陪伴大家共克时艰 发布了首份中文版用户手册 重新梳理了文档布局并翻译成了中文 环境准备 在非 Ubuntu 平台,请提前自行安装好 docker,可参考Docker for Mac、Docker for Windows。 如果是老版本的 Windows,可以用Docker Toolbox,也可以通过 Virtualbox 或 Vmware 自行安装 Ubuntu。 国内的同学请务必使用国内的 Docker 镜像服务,否则无法正常下载镜像,推荐参考阿里云镜像配置文档。 极速体验 该版本依赖最新的 Cloud Lab 和 docker 镜像: $ git clone https://gitee.com/tinylab/cloud-lab.git $ cd cloud-lab $ tools/docker/pull linux-lab # 确保更新 docker 镜像 $ tools/docker/run linux-lab 已经下载过的,请更新到最新版本并重启 Linux Lab: $ cd cloud-lab && git pull $ tools/docker/update linux-lab $ tools/docker/rerun linux-lab 进去以后,打开控制台,敲入如下命令即可启动一个板子(自动下载预编译的版本): $ make boot 一键编译(自动下载源码、检出版本、打补丁、配置、编译): $ make boot build=kernel 关键特性 Linux Lab 具备如下特性: 支持 3 大操作系统(Windows、MacOS、Linux),可以轻松在这三大操作系统下使用。 支持 7+ 大处理器架构(X86、ARM、MIPS、PPC、CSKY,RISC-V, LOONGSON),其中 LOONGSON 和 CSKY 为国产处理器。 支持 15+ 款开发板(i386/pc, x86_64/pc, arm/versatilepb, arm/vexpress-a9, ppc/g3beige, mips/malta, aarch64/virt, aarch64/raspi3, riscv32/virt, riscv64/virt, csky/virt, loongson/ls1b, loongson/ls2k, loongson/ls232, loongson/ls3a7a)。 支持 5 种登陆方式(docker, ssh, vnc,webssh, webvnc),可以本地访问,也可以远程访问。 集成了 5 大组件(Qemu、U-boot、Buildroot、Linux、Toolchain),都有预编译版本。 内置了 5 大平台,32 位和 64 位共 10 个 Hello World 汇编语言例程,见examples/assembly。 可以学习处理器指令集、Qemu、Shell、汇编、C、Linux 内核、嵌入式 Linux。 支持 Debugging 和 Testing。 host & guest 双侧免 root 使用。 更多信息: 项目首页 Homepage:http://tinylab.org/linux-lab 项目社群 联系微信:tinylab 联系公号:泰晓科技 Linux Lab 用户交流群 Linux Lab 开发者 项目仓库 Gitee:https://gitee.com/tinylab/linux-lab Github:https://github.com/tinyclub/linux-lab 项目插件 CSKY(中天微):https://gitee.com/tinylab/csky LOONGSON(龙芯):https://gitee.com/loongsonlab/loongson 演示视频 基本用法:Linux 快速上手 学习汇编:AT&T 汇编上手 学习Uboot:Uboot 快速上手 ARM 开发:在 arm/vexpress-a9 上运行 Ubuntu 18.04 LTS RISC-V开发:使用 riscv32/virt 和 riscv64/virt 开发板 龙芯开发:在 Linux Lab 上使用龙芯 ls2k 平台 特性开发:一条命令测试和体验某个内核特性 模块开发:一条命令配置、编译和测试内核模块 内核调试:所有板子的调试功能自测视频 内核测试:所有当前预置板子的启动过程自测视频 该项目完全开源,以 GPL 2.0 协议发布,欢迎所有高校、企业、个人用户使用或者参与开发。 欢迎通过微信号(tinylab)联系我们,联系后可以获邀进Linux Lab 用户交流群和Linux Lab 开发者群,还将获赠 Linux Lab 安装文档和 Linux Lab 大会演讲幻灯片。

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

我是如何把SpringBoot项目的并发提升十倍量级的

云栖号:https://yqh.aliyun.com第一手的上云资讯,不同行业精选的上云企业案例库,基于众多成功案例萃取而成的最佳实践,助力您上云决策! 背景 生产环境偶尔会有一些慢请求导致系统性能下降,吞吐量下降,下面介绍几种优化建议。 方案 1、undertow替换tomcat 电子商务类型网站大多都是短请求,一般响应时间都在100ms,这时可以将web容器从tomcat替换为undertow,下面介绍下步骤:1、增加pom配置 <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> <exclusions> <exclusion> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-tomcat</artifactid> </exclusion> </exclusions> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-undertow</artifactid> </dependency> 2、增加相关配置 server: undertow: direct-buffers: true io-threads: 4 worker-threads: 160 重新启动可以在控制台看到容器已经切换为undertow了 2、缓存 将部分热点数据或者静态数据放到本地缓存或者redis中,如果有需要可以定时更新缓存数据 3、异步 在代码过程中我们很多代码都不需要等返回结果,也就是部分代码是可以并行执行,这个时候可以使用异步,最简单的方案是使用springboot提供的@Async注解,当然也可以通过线程池来实现,下面简单介绍下异步步骤。1、pom依赖 一般springboot引入web相关依赖就行 <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> 2、在启动类中增加@EnableAsync注解 @EnableAsync @SpringBootApplication public class AppApplication { public static void main(String[] args) { SpringApplication.run(AppApplication.class, args); } } 3、需要时在指定方法中增加@Async注解,如果是需要等待返回值,则demo如下 @Async public Future<string> doReturn(int i){ try { // 这个方法需要调用500毫秒 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } / 消息汇总 return new AsyncResult&lt;&gt;("异步调用"); } 4、如果有线程变量或者logback中的mdc,可以增加传递 import org.slf4j.MDC; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskDecorator; import org.springframework.scheduling.annotation.AsyncConfigurerSupport; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.Map; import java.util.concurrent.Executor; /** * @Description: */ @EnableAsync @Configuration public class AsyncConfig extends AsyncConfigurerSupport { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setTaskDecorator(new MdcTaskDecorator()); executor.initialize(); return executor; } } class MdcTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { Map<string, string> contextMap = MDC.getCopyOfContextMap(); return () -&gt; { try { MDC.setContextMap(contextMap); runnable.run(); } finally { MDC.clear(); } }; } } 5、有时候异步需要增加阻塞 import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; @Configuration @Slf4j public class TaskExecutorConfig { @Bean("localDbThreadPoolTaskExecutor") public Executor threadPoolTaskExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(200); taskExecutor.setQueueCapacity(200); taskExecutor.setKeepAliveSeconds(100); taskExecutor.setThreadNamePrefix("LocalDbTaskThreadPool"); taskExecutor.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor executor) -&gt; { if (!executor.isShutdown()) { try { Thread.sleep(300); executor.getQueue().put(r); } catch (InterruptedException e) { log.error(e.toString(), e); Thread.currentThread().interrupt(); } } } ); taskExecutor.initialize(); return taskExecutor; } } 4、业务拆分 可以将比较耗时或者不同的业务拆分出来提供单节点的吞吐量 5、集成消息队列 有很多场景对数据实时性要求不那么强的,或者对业务进行业务容错处理时可以将消息发送到kafka,然后延时消费。举个例子,根据条件查询指定用户发送推送消息,这里可以时按时、按天、按月等等,这时就 云栖号:https://yqh.aliyun.com第一手的上云资讯,不同行业精选的上云企业案例库,基于众多成功案例萃取而成的最佳实践,助力您上云决策! 原文发布时间:2020-02-19本文作者:lipengHeke本文来自:“互联网架构师公众号”,了解相关信息可以关注“互联网架构师”

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

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

Rocky Linux

Rocky Linux

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

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册