线程

Linux网络编程 - 子线程使用poll处理连接 I/O事件(高并发高性能进阶篇)

流过昼夜 提交于 2020-03-07 10:18:07
这一篇我们就将 acceptor 上的连接建立事件和已建立连接的 I/O 事件分离,形成所谓的 主 - 从 reactor 模式 。 主 - 从 reactor 模式 主 - 从这个模式的核心思想是,主反应堆线程只负责分发 Acceptor 连接建立,已连接套接字上的 I/O 事件交给 sub-reactor 负责分发。其中 sub-reactor 的数量,可以根据 CPU 的核数来灵活设置 。 多个反应堆线程同时在工作,这大大增强了 I/O 分发处理的效率,并且同一个套接字事件分发只会出现在一个反应堆线程中,这会大大减少并发处理的锁开销。 来解释一下这张图,我们的 主反应堆线程一直在感知连接建立的事件 ,如果有连接成功建立,主反应堆线程 通过 accept 方法获取已连接套接字 ,接下来会 按照一定的算法 选取一个从反应堆线程,并 把已连接套接字加入到选择好的从反应堆线程中 。 主反应堆线程唯一的工作,就是调用 accept 获取已连接套接字,以及将已连接套接字加入到从反应堆线程中。不过,这里还有一个小问题,主反应堆线程和从反应堆线程,是 两个不同的线程,如何把已连接套接字加入到另外一个线程中呢 ?这是高性能网络程序框架要解决的问题,在后面,将会给出这个问题的答案。 主 - 从 reactor+worker threads 模式 如果说主 - 从 reactor 模式解决了 I

java 多线程 基础总结

梦想与她 提交于 2020-03-07 09:59:34
Java多线程实例 3种实现方法 Java中的多线程有三种实现方式: 1.继承Thread类,重写run方法。Thread本质上也是一个实现了Runnable的实例,他代表一个线程的实例,并且启动线程的唯一方法就是通过Thread类的start方法。 2.实现Runnable接口,并实现该接口的run()方法.创建一个Thread对象,用实现的Runnable接口的对象作为参数实例化Thread对象,调用此对象的start方法。 3.实现Callable接口,重写call方法。Callable接口与Runnable接口的功能类似,但提供了比Runnable更强大的功能。有以下三点 1).Callable可以在人物结束后提供一个返回值,Runnable没有提供这个功能。 2).Callable中的call方法可以抛出异常,而Runnable的run方法不能抛出异常。 3).运行Callable可以拿到一个Future对象,表示异步计算的结果,提供了检查计算是否完成的方法。 需要注意的是,无论用那种方式实现了多线程,调用start方法并不意味着立即执行多线程代码,而是使得线程变为可运行状态。 run start的区别 start方法是启动一个线程,而线程中的run方法来完成实际的操作。 如果开发人员直接调用run方法,那么就会将这个方法当作一个普通函数来调用,并没有多开辟线程

ConcurrentHashMap 的实现原理

若如初见. 提交于 2020-03-07 08:57:19
概述 我们在之前的博文中了解到关于 HashMap 和 Hashtable 这两种集合。其中 HashMap 是非线程安全的,当我们只有一个线程在使用 HashMap 的时候,自然不会有问题,但如果涉及到多个线程,并且有读有写的过程中,HashMap 就不能满足我们的需要了(fail-fast)。在不考虑性能问题的时候,我们的解决方案有 Hashtable 或者Collections.synchronizedMap(hashMap),这两种方式基本都是对整个 hash 表结构做锁定操作的,这样在锁表的期间,别的线程就需要等待了,无疑性能不高。 所以我们在本文中学习一个 util.concurrent 包的重要成员,ConcurrentHashMap。 ConcurrentHashMap 的实现是依赖于 Java 内存模型,所以我们在了解 ConcurrentHashMap 的前提是必须了解Java 内存模型。但 Java 内存模型并不是本文的重点,所以我假设读者已经对 Java 内存模型有所了解。 ConcurrentHashMap 分析 ConcurrentHashMap 的结构是比较复杂的,都深究去本质,其实也就是数组和链表而已。我们由浅入深慢慢的分析其结构。 先简单分析一下,ConcurrentHashMap 的成员变量中,包含了一个 Segment 的数组( final

Thread中,join()方法

半城伤御伤魂 提交于 2020-03-07 06:37:09
Thread中,join()方法的作用是调用线程等待该线程完成后,才能继续用下运行。 public static void main(String[] args) throws InterruptedException { System.out.println("main start"); Thread t1 = new Thread(new Worker("thread-1")); t1.start(); t1.join(); System.out.println("main end"); } 在上面的例子中,main线程要等到t1线程运行结束后,才会输出“main end”。如果不加t1.join(),main线程和t1线程是并行的。而加上t1.join(),程序就变成是顺序执行了。 我们在用到join()的时候,通常都是main线程等到其他多个线程执行完毕后再继续执行。其他多个线程之间并不需要互相等待。 下面这段代码并没有实现让其他线程并发执行,线程是顺序执行的。 public static void main(String[] args) throws InterruptedException { System.out.println("main start"); Thread t1 = new Thread(new Worker("thread-1")); Thread

线程的启动的两种方法,Runnable接口,run()的调用

一曲冷凌霜 提交于 2020-03-07 06:29:51
实现并启动线程有两种方法 1、写一个类继承自Thread类,重写run方法。用start方法启动线程 2、写一个类实现Runnable接口,实现run方法。用new Thread(Runnable target).start()方法来启动 多线程原理: 相当于玩游戏机,只有一个游戏机(cpu),可是有很多人要玩,于是,start是排队!等CPU选中你就是轮到你,你就run(),当CPU的运行的时间片执行完,这个线程就继续排队,等待下一次的run()。 调用start()后,线程会被放到等待队列,等待CPU调度,并不一定要马上开始执行,只是将这个线程置于可动行状态。然后通过JVM,线程Thread会调用run()方法,执行本线程的线程体。 先调用start后调用run,这么麻烦,为了不直接调用run? 就是为了实现多线程的优点,没这个start不行。 1. start()方法来启动线程,真正实现了多线程运行。 这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码;通过调用Thread类的start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行操作的, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。 2. run(

jvm学习006 jvm内存结构分配

穿精又带淫゛_ 提交于 2020-03-07 06:13:10
主要内容如下: JVM启动流程 JVM基本结构 内存模型 编译和解释运行的概念 一、JVM启动流程: JVM启动时,是由java命令/javaw命令来启动的。 二、JVM基本结构: JVM基本结构图: 《深入理解Java虚拟机(第二版)》中的描述是下面这个样子的: Java中的内存分配: Java程序在运行时,需要在内存中的分配空间。 为了提高运算效率,就对数据进行了不同空间的划分 ,因为每一片区域都有特定的处理数据方式和内存管理方式。 具体划分为如下 5个内存空间 :(非常重要) 栈 :存放 局部变量 堆 :存放所有 new出来的东西 方法区:被虚拟机加载的类信息、常量、静态常量等。 程序计数器(和系统相关) 本地方法栈 1、程序计数器: 每个线程拥有一个PC寄存器 在线程创建时创建 指向下一条指令的地址 执行本地方法时,PC的值为undefined 2、方法区: 保存装载的类信息   类型的常量池   字段,方法信息   方法字节码 通常和永久区(Perm)关联在一起 3、堆内存: 和程序开发密切相关 应用系统对象都保存在Java堆中 所有线程共享Java堆 对分代GC来说,堆也是分代的 GC管理的主要区域 现在的GC基本都采用分代收集算法,如果是分代的,那么堆也是分代的。如果堆是分代的,那堆空间应该是下面这个样子: 上图是堆的基本结构,在之后的文章中再进行详解。 4、栈内存:

MYSQL 逻辑架构

旧巷老猫 提交于 2020-03-07 05:29:30
前言 》 Mysql并非尽善尽美,但足够灵活,能适应高要求环境,如Web应用。 》 Mysql在众多平台上运行良好,支持多种数据类型,但不支持对象类型(Mongodb支持) 》 Mysql的存储引擎可以基于表建立,以满足对数据存储,性能,特征及其他特性的各种需要。 架构逻辑视图 每个虚线框为一层,总共三层。 第一层,服务层(为客户端服务):为请求做连接处理,授权认证,安全等。 第二层,核心层:查询解析,分析,优化,缓存,提供内建函数;存储过程,触发器,视图。 第三层,存储引擎层,不光做存储和提取数据,而且针对特殊数据引擎还要做事务处理。 连接管理与安全性(第一层 服务层) > 处理流程 Δ 每个连接的查询都在一个进程中的线程完成。 Δ 服务器负责缓存线程,所以服务层不需要为每个连接新建线程。 > 认证流程    优化与执行 > 在解析查询之前,服务器会“询问”是否进行了查询缓存(只能缓存SELECT语句和相应结果)。缓存过的直接返回结果,未缓存的就需要进行解析查询,优化,重新执行返回结果。 > 解析查询时会创建一个内部数据结构(树),然后对其进行各种优化。 > 优化:重写查询,决定查询的读表顺序,选择需使用的索引。 》 Mysql并非尽善尽美,但足够灵活,能适应高要求环境,如Web应用。 》 Mysql在众多平台上运行良好,支持多种数据类型,但不支持对象类型(Mongodb支持)

mysql 逻辑架构

别说谁变了你拦得住时间么 提交于 2020-03-07 05:27:50
1、mysql是基于网络的客户端/服务器架构,服务器上层是连接线程,解析器,查询缓存,下层是存储引擎。 2、每个客户端连接,服务器都有一个对应的线程,这个线程只为这个连接查询服务,高版本的mysql支持线程池,使用少量的线程服务大量的连接。 3、服务器收到请求,会解析查询,建立解析树,然后对其优化,包括重写查询,决定表的读取顺序,选择合适的索引等。当然用户可以使用特殊的关键字提示优化器,影响优化器的决策。通过explain或者desc ,可以查询服务器是怎么优化的。对于select语句,mysql会建立查询缓存,mysql先检查查询缓存,如果能命中,直接在查询缓存中取数据。否则,进行解析,优化,执行的过程。 来源: https://www.cnblogs.com/nzbbody/p/4542150.html

Java 可重入锁

久未见 提交于 2020-03-07 04:51:16
可重入锁: 如果某个线程试图获取一个已经由它自己持有的锁时,这个请求会立刻成功,并且会将这个锁的计数值加1,而当线程退出同步代码块时,计数器将会递减,当计数值为0时,释放锁。 如果没有可重入锁的支持,在第二次企图获得锁时会进入死锁状态。 通俗来说:当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞。 可重入锁举例: class ReentrantLockTest { public synchronized void a ( ) { b ( ) ; } public synchronized void b ( ) { } public synchronized void all ( ) { this . a ( ) ; } } 下面代码为例,若锁不可重入,则会在第二次获得锁时死锁。 public class LockTest { public void test ( ) { //第一次获得锁 synchronized ( this ) { while ( true ) { //第二次获得锁 synchronized ( this ) { System . out . println ( "ReentrantLock" ) ; } try { Thread . sleep ( 1000 ) ; } catch

设计模式——单例模式

≡放荡痞女 提交于 2020-03-07 04:14:59
关于单例模式,这是面试时最容易遇到的问题。当时以为很简单的内容,深挖一下,也可以关联出类加载、序列化等知识。 饿汉式 我们先来看看基本的饿汉式写法: public class Hungry { private static final Hungry instance = new Hungry(); private Hungry() {} public Hungry getInstance() { return instance; } } 优点:写法简答,不需要考虑多线程等问题。 缺点:如果该实例从未被用到的话,相当于资源浪费。 static 代码块 我们也可以用 static 代码块的方式,实现饿汉式: public class Hungry { private static final Hungry instance; static { instance = new Hungry(); } private Hungry() {} public Hungry getInstance() { return instance; } } 这就是利用了 static 代码块的功能: 它是随着类的加载而执行,只执行一次,并优先于主函数。 懒汉式 我们先来看看基本的懒汉式写法: public class Lazy { private static volatile Lazy instance;