首页 文章 精选 留言 我的

精选列表

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

高并发之——线程与多线程

一、线程与多线程 1.线程 在操作系统中,线程是比进程更小的能够独立运行的基本单位。同时,它也是CPU调度的基本单位。线程本身基本上不拥有系统资源,只是拥有一些在运行时需要用到的系统资源,例如程序计数器,寄存器和栈等。一个进程中的所有线程可以共享进程中的所有资源。 2.多线程 多线程可以理解为在同一个程序中能够同时运行多个不同的线程来执行不同的任务,这些线程可以同时利用CPU的多个核心运行。多线程编程能够最大限度的利用CPU的资源。如果某一个线程的处理不需要占用CPU资源时(例如IO线程),可以使当前线程让出CPU资源来让其他线程能够获取到CPU资源,进而能够执行其他线程对应的任务,达到最大化利用CPU资源的目的。 二、实现线程的方式 在Java中,实现线程的方式大体上分为三种,通过继承Thread类、实现Runnable接口,实现Callable接口。简单的示例代码分别如下所示。 继承Thread类代码 package io.binghe.concurrent.executor.test; /** * @author binghe * @version 1.0.0 * @description 继承Thread实现线程 */ public class ThreadTest extends Thread { @Override public void run() { //TODO 在此写在线程中执行的业务逻辑 } } 实现Runnable接口代码 package io.binghe.concurrent.executor.test; /** * @author binghe * @version 1.0.0 * @description 实现Runnable实现线程 */ public class RunnableTest implements Runnable { @Override public void run() { //TODO 在此写在线程中执行的业务逻辑 } } 实现Callable接口代码 package io.binghe.concurrent.executor.test; import java.util.concurrent.Callable; /** * @author binghe * @version 1.0.0 * @description 实现Callable实现线程 */ public class CallableTest implements Callable<String> { @Override public String call() throws Exception { //TODO 在此写在线程中执行的业务逻辑 return null; } } 三、线程的生命周期 1.生命周期 一个线程从创建,到最终的消亡,需要经历多种不同的状态,而这些不同的线程状态,由始至终也构成了线程生命周期的不同阶段。线程的生命周期可以总结为下图。 其中,几个重要的状态如下所示。 NEW:初始状态,线程被构建,但是还没有调用start()方法。 RUNNABLE:可运行状态,可运行状态可以包括:运行中状态和就绪状态。 BLOCKED:阻塞状态,处于这个状态的线程需要等待其他线程释放锁或者等待进入synchronized。 WAITING:表示等待状态,处于该状态的线程需要等待其他线程对其进行通知或中断等操作,进而进入下一个状态。 TIME_WAITING:超时等待状态。可以在一定的时间自行返回。 TERMINATED:终止状态,当前线程执行完毕。 2.代码示例 为了更好的理解线程的生命周期,以及生命周期中的各个状态,接下来使用代码示例来输出线程的每个状态信息。 WaitingTime 创建WaitingTime类,在while(true)循环中调用TimeUnit.SECONDS.sleep(long)方法来验证线程的TIMED_WARTING状态,代码如下所示。 package io.binghe.concurrent.executor.state; import java.util.concurrent.TimeUnit; /** * @author binghe * @version 1.0.0 * @description 线程不断休眠 */ public class WaitingTime implements Runnable{ @Override public void run() { while (true){ waitSecond(200); } } //线程等待多少秒 public static final void waitSecond(long seconds){ try { TimeUnit.SECONDS.sleep(seconds); } catch (InterruptedException e) { e.printStackTrace(); } } } WaitingState 创建WaitingState类,此线程会在一个while(true)循环中,获取当前类Class对象的synchronized锁,也就是说,这个类无论创建多少个实例,synchronized锁都是同一个,并且线程会处于等待状态。接下来,在synchronized中使用当前类的Class对象的wait()方法,来验证线程的WAITING状态,代码如下所示。 package io.binghe.concurrent.executor.state; /** * @author binghe * @version 1.0.0 * @description 线程在Warting上等待 */ public class WaitingState implements Runnable { @Override public void run() { while (true){ synchronized (WaitingState.class){ try { WaitingState.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } BlockedThread BlockedThread主要是在synchronized代码块中的while(true)循环中调用TimeUnit.SECONDS.sleep(long)方法来验证线程的BLOCKED状态。当启动两个BlockedThread线程时,首先启动的线程会处于TIMED_WAITING状态,后启动的线程会处于BLOCKED状态。代码如下所示。 package io.binghe.concurrent.executor.state; /** * @author binghe * @version 1.0.0 * @description 加锁后不再释放锁 */ public class BlockedThread implements Runnable { @Override public void run() { synchronized (BlockedThread.class){ while (true){ WaitingTime.waitSecond(100); } } } } ThreadState 启动各个线程,验证各个线程输出的状态,代码如下所示。 package io.binghe.concurrent.executor.state; /** * @author binghe * @version 1.0.0 * @description 线程的各种状态,测试线程的生命周期 */ public class ThreadState { public static void main(String[] args){ new Thread(new WaitingTime(), "WaitingTimeThread").start(); new Thread(new WaitingState(), "WaitingStateThread").start(); //BlockedThread-01线程会抢到锁,BlockedThread-02线程会阻塞 new Thread(new BlockedThread(), "BlockedThread-01").start(); new Thread(new BlockedThread(), "BlockedThread-02").start(); } } 运行ThreadState类,如下所示。 可以看到,未输出任何结果信息。可以在命令行输入“jps”命令来查看运行的Java进程。 c:\>jps 21584 Jps 17828 KotlinCompileDaemon 12284 Launcher 24572 28492 ThreadState 可以看到ThreadSate进程的进程号为28492,接下来,输入“jstack 28492”来查看ThreadSate进程栈的信息,如下所示。 c:\>jstack 28492 2020-02-15 00:27:08 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.202-b08 mixed mode): "DestroyJavaVM" #16 prio=5 os_prio=0 tid=0x000000001ca05000 nid=0x1a4 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "BlockedThread-02" #15 prio=5 os_prio=0 tid=0x000000001ca04800 nid=0x6eb0 waiting for monitor entry [0x000000001da4f000] java.lang.Thread.State: BLOCKED (on object monitor) at io.binghe.concurrent.executor.state.BlockedThread.run(BlockedThread.java:28) - waiting to lock <0x0000000780a7e4e8> (a java.lang.Class for io.binghe.concurrent.executor.state.BlockedThread) at java.lang.Thread.run(Thread.java:748) "BlockedThread-01" #14 prio=5 os_prio=0 tid=0x000000001ca01800 nid=0x6e28 waiting on condition [0x000000001d94f000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java:340) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) at io.binghe.concurrent.executor.state.WaitingTime.waitSecond(WaitingTime.java:36) at io.binghe.concurrent.executor.state.BlockedThread.run(BlockedThread.java:28) - locked <0x0000000780a7e4e8> (a java.lang.Class for io.binghe.concurrent.executor.state.BlockedThread) at java.lang.Thread.run(Thread.java:748) "WaitingStateThread" #13 prio=5 os_prio=0 tid=0x000000001ca06000 nid=0x6fe4 in Object.wait() [0x000000001d84f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000780a7b488> (a java.lang.Class for io.binghe.concurrent.executor.state.WaitingState) at java.lang.Object.wait(Object.java:502) at io.binghe.concurrent.executor.state.WaitingState.run(WaitingState.java:29) - locked <0x0000000780a7b488> (a java.lang.Class for io.binghe.concurrent.executor.state.WaitingState) at java.lang.Thread.run(Thread.java:748) "WaitingTimeThread" #12 prio=5 os_prio=0 tid=0x000000001c9f8800 nid=0x3858 waiting on condition [0x000000001d74f000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java:340) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) at io.binghe.concurrent.executor.state.WaitingTime.waitSecond(WaitingTime.java:36) at io.binghe.concurrent.executor.state.WaitingTime.run(WaitingTime.java:29) at java.lang.Thread.run(Thread.java:748) "Service Thread" #11 daemon prio=9 os_prio=0 tid=0x000000001c935000 nid=0x6864 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x000000001c88c800 nid=0x6a28 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x000000001c880000 nid=0x6498 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x000000001c87c000 nid=0x693c waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x000000001c87b800 nid=0x5d00 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x000000001c862000 nid=0x6034 runnable [0x000000001d04e000] java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) - locked <0x0000000780b2fd88> (a java.io.InputStreamReader) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:161) at java.io.BufferedReader.readLine(BufferedReader.java:324) - locked <0x0000000780b2fd88> (a java.io.InputStreamReader) at java.io.BufferedReader.readLine(BufferedReader.java:389) at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64) "Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001c788800 nid=0x6794 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001c7e3800 nid=0x3354 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001c771000 nid=0x6968 in Object.wait() [0x000000001cd4f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000780908ed0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) - locked <0x0000000780908ed0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216) "Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001c770800 nid=0x6590 in Object.wait() [0x000000001cc4f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000780906bf8> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x0000000780906bf8> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) "VM Thread" os_prio=2 tid=0x000000001a979800 nid=0x5c2c runnable "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000033b9000 nid=0x4dc0 runnable "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000033ba800 nid=0x6690 runnable "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000033bc000 nid=0x30b0 runnable "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000033be800 nid=0x6f68 runnable "GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00000000033c1000 nid=0x6478 runnable "GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00000000033c2000 nid=0x4fe4 runnable "GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00000000033c5000 nid=0x584 runnable "GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00000000033c6800 nid=0x6988 runnable "VM Periodic Task Thread" os_prio=2 tid=0x000000001c959800 nid=0x645c waiting on condition JNI global references: 12 由以上输出的信息可以看出:名称为WaitingTimeThread的线程处于TIMED_WAITING状态;名称为WaitingStateThread的线程处于WAITING状态;名称为BlockedThread-01的线程处于TIMED_WAITING状态;名称为BlockedThread-02的线程处于BLOCKED状态。 注意:使用jps结合jstack命令可以分析线上生产环境的Java进程的异常信息。 也可以直接点击IDEA下图所示的图表直接打印出线程的堆栈信息 输出的结果信息与使用“jstack 进程号”命令输出的信息基本一致。

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

王者荣耀高并发背后的故事

“王者荣耀”是一款国民级手机游戏,用户体量巨大,而且一直保持着较高的更新频率。这种业务场景下,突发也变得非常频繁,然而业务体验是至关重要的,使用CDN必不可少。类似地,经常有带宽突发的场景,比如新闻爆点视频、大型直播活动、热门影视剧上线、热门游戏等应用发布。同时,由于家庭带宽和移动网络的快速升级,突发带宽量级越来越大,经常达到Tb级,甚至10Tb 。如何快速、低成本地保障业务突发,成为CDN的一大挑战。 2007年,腾讯自建CDN启用,接入了第一个业务腾讯网。到现在CDN带宽量级,从最早的数十Gb,发展到现在的数十Tb;单业务的带宽也越来越大,大部分业务常量带宽在几百Gb,部分突发业务达到了10Tb。网络的快速升级,移动用户爆发式增长,以及视频类业务包括点播和直播的兴起,使得业务突发越来越频繁,突发带宽越来越高,对CDN的要求也越来越高。 自建CDN得益于腾讯业务的蓬勃发展,先后支持了游戏下载、流媒体视频加速、春节红包等腾讯内部业务;2014年腾讯将CDN全面能力开放,成为腾讯云CDN产品,除承载内部业务外,也开始接入第三方客户,比如快手点播、斗鱼直播等。以上各种业务都有突发场景,也有很强的成本诉求,在如何低成本地保障业务突发,腾讯CDN积累了丰富的经验。接下来就挑战和问题、解决方案、效果三个方面来解析。 一、挑战和问题 下面将从业务特点开始,分析目前存在的挑战和问题。 1、 业务特点和挑战 CDN多样化的场景,注定了突发业务充满挑战。突发业务具有体量大、场景多样化、 无规律等特点。 a) 体量大:突发业务带宽大部分都超过Tb,部分甚至达到了10T ; b) 场景多样化:点播中的热剧和新闻爆点;直播中的LOL/KPL/DOTA2等游戏直播,NBA/世界杯等体育直播,演唱会等综艺直播;应用下载中的王者荣耀等游戏下载;静态网页加速中的红包活动、电商促销等; c) 无规律:部分突发活动无法预知,活动快要开始或已经开始了才知道,比如新闻爆点。 体量大,需要准备更多的资源;场景多样化,需要满足不同的资源需求;无规律性则对我们的扩容效率提了很高的要求。 2、 目前存在的问题 仅仅为了满足业务突发需求而储备大量的资源,成本太高,会造成资源极大的浪费。所以一般会通过复用资源来应对业务突发。但是直接复用资源,存在两个问题: a) 只能复用部分资源:CDN业务,一般按业务类型来区分平台和资源使用,主要原因是不同业务类型对资源需求不同,比如点播类需要更多的存储;有较多https请求的静态页面类,则需要更多CPU资源。这种限制使得资源无法充分利用,加大了资源准备的难度。比如视频突发主要使用视频Buffer,而下载类和网页类Buffer无法直接使用,这限制了Buffer的大小。即使复用同类型资源,因为涉及多个业务资源的协调,准备时间一般会超过两天,无法应对临时突发; b) 无法降低成本:另外针对部分突发业务,比如游戏应用下载,带宽高峰期在上午和中午,如果只使用本平台资源,会导致结算带宽明显上涨,从而增加成本。无法利用同其他业务错峰的特点来降低结算带宽。 二、解决方案 腾讯云CDN通过虚拟化复用现有资源,搭建全业务通用的突发池,所有平台共享Buffer。 突发池中的设备为Docker虚拟机,虚拟机有不同的规格,只要业务有需求,都可以按需使用。突发池中的带宽储备达到了10Tb,基本能满足所有业务突发需求 。任何业务有突发需求,配合自动化上架接口,可在10分钟完成10Tb突发池的扩容。 1、 突发池系统架构 突发池系统架构见图1: 图 1突发池系统架构 (a) 突发池:在各平台物理机的上层,由Docker虚拟机组成的资源池,对CPU/内存/磁盘等使用进行了限制,防止对物理机造成影响。原有业务依然部署在物理机上,不用调整。 (b) 自动化部署和监控系统: 能根据业务实际需求,自动预测需求并扩容 。所有的突发需求,都能在10分钟内扩容完成。针对点播/下载业务,自动分发热点文件,降低回源带宽。 (c) 调度系统:突发业务的突发性和体量大两个特点,使得相比域名调度系统,直通车更占优势。直通车调度更灵活,生效时间快,能达到分钟级。 虚拟机和物理机部署了上报Agent,业务信息和服务器负载每分钟都会上报到监控系统。监控系统会根据历史带宽预测一个值,并与当前带宽比较,如果当前带宽超过预测值的50%,则认为有突发。根据带宽上涨的比例,系统会自动从突发池中扩容相应数据的设备。针对提前准备的突发活动,运维可以指定带宽需求量,之后系统便会自动计算设备需求并扩容。 分钟粒度上报的服务器负载信息则为监控系统做调度决策提供了依据。系统会依据机房剩余带宽、服务器带宽、CPU、IO等综合信息决定虚拟机是否需要从直通车中启用或者禁用。用户访问时先请求直通车调度系统,直通车会根据调度策略返回一个302地址,302地址中为实际CDN资源地址。用户跳转到302地址,并获取实际内容。 2、技术优化 使用虚拟化技术复用资源的重要前提是,不影响现有业务。这就要求对资源有充分的隔离,比如CPU/磁盘,以及对带宽的使用。下面是实现过程中存在的几个问题及解决方案: 精准控制单机负载:负载过高会影响业务质量,需要对单机负载进行精准的控制。 解决方案: (a) 配额系统:直通车中有配额系统,对每个虚拟机可使用的资源做了限制,包括CPU/IO和带宽。监控系统中上报的信息,结合配额系统,可以确保服务器负载被限定在制定的范围内,粒度为分钟级。 (b) 部分请求返回302:对CPU/带宽/IO等做了限制后,应用程序能根据母机当前负载,实时判断是否处理一个请求。如果负载在限制范围内,直接处理;如果负载超出限制,则返回302,使用户跳转到直通车的调度地址,这样能在尽量不影响业务质量的情况对负载做精准控制。程序层面对负载的实时控制,是配额系统的有效补充。 (c) 网卡流量控制:在极端情况下,业务带宽超过设定阈值,这时虚拟网卡会主动丢包,避免对母机造成影响。 限制磁盘大小:Docker在ext3/ext4文件系统中无法对文件/目录级别进行磁盘大小限制。 解决方案: 由于腾讯云CDN业务基本都是使用ext3/ext4文件系统,这种情况下Docker只能对根据用户或用户组对磁盘进行限制,但现网业务都是直接在root环境下使用。这里我们使用loop device来解决磁盘大小限制问题。虚拟机中突发业务使用挂载在loop device上的目录,这样就可以间接限制磁盘大小,防止使用太多磁盘影响其他业务。 CPU绑定:默认是绑定所有CPU,部分单CPU负载高会影响母机业务。 解决方案: 通过脚本每分钟采集一次系统所有单CPU负载,为避免频繁调整和受毛刺数据影响,取15分钟的均值。最后选取负载较低的部分核,并通过配置文件cpuset.cpus来动态绑定,将虚拟机对母机业务影响降低到最小,并且能充分利用资源。 效果 突发池上线后,高效支持了王者荣耀下载、NBA直播、KPL/LPL游戏直播等多次大型突发活动,节约成本2000万。通过共享buffer,搭建突发池能显著提高突发能力和降低成本。 总结 腾讯云CDN通过Docker技术复用资源,搭建Tb级别突发池,能支持直播、点播、静态等各种业务突发,能自动检测到业务突发需求并在10分钟内完成资源扩容,具有发布快,成本低等特点。资源复用能提高资源利用率,为业务提供极大的突发池,但要注意复用业务之间不能相互影响,这需要对服务器进行实时的监控和及时的调度。另外还有一些待改进的地方,比如内核参数基于容器隔离,方便不同业务调优;部分业务客户端不支持302跳转,调度系统需要支持域名调度方式。 原文链接:http://bigdata.evget.com/post/1896.html

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

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等操作系统。

用户登录
用户注册