线程

Python数据库连接池DBUtils

我们两清 提交于 2020-04-06 21:21:37
DBUtils是Python的一个用于实现数据库连接池的模块。 此连接池有两种连接模式:   模式一:为每个线程创建一个连接,线程即使调用了close方法,也不会关闭,只是把连接重新放到连接池,供自己线程再次使用。当线程终止时,连接自动关闭。 POOL = PersistentDB( creator=pymysql, # 使用链接数据库的模块 maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."] ping=0, # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always closeable=False, # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接

线程:安全终止与重启

痞子三分冷 提交于 2020-04-06 20:16:40
之前在一篇文章中提到过线程的安全终止的方法,大致的意思就是自定义一个boolean 类型的 volatile 变量,通过控制这个变量来终止线程。 class UiThread extends Thread { private volatile boolean isRun = true; @Override public void run() { while (isRun) { //你的操作 } } public void close() { isRun = false; } } 但是这种做法有个弊端,那就是这种终止方法的实时性很低。 如果在while里面的代码执行时间很长,比如需要10分钟,但是在这10分钟内,调用了close方法,isRun变成了false,可是这时候程序运行到while括号里面的代码段,只有运行完这个括号里面的代码段,才会判断isRun,这样从调用close进行终止,到程序实际终止的时延很大,对于一些实时性要求高,或则是事务类型的操作这样显然是不行的。 因此,本文再介绍一种实时性比较好的做法,使用interrupt,以前也一直没看明白,今天总算搞懂了。。。 首先,看看 Thread的interrupt方法解释:   void java.lang.Thread.interrupt() Posts an interrupt request to this

Java内存泄露

亡梦爱人 提交于 2020-04-06 19:15:39
一、概述 虽然Java有垃圾收集器帮助实现内存自动管理,虽然GC有效的处理了大部分内存,但是并不能完全保证内存的不泄露。 二、内存泄露 内存泄露就是堆内存中不再使用的对象,但是垃圾回收期无法从内存中删除他们的情况,因此他们会被不必要的一直存在。,这种情况会耗尽内存资源并降低系统性能,最终以OOM终止。 垃圾回收器会定期删除未引用的对象,但它永远不会收集那些仍在引用的对象。 内存泄露的症状: 应用程序长时间连续运行时性能严重下降; 应用程序中的OutOfMemoryError堆错误; 自发且奇怪的应用程序崩溃; 应用程序偶尔会耗尽连接对象。 三、Java中内存泄露类型 1、static字段引起的内存泄露 大量使用static字段会潜在的导致内存泄露,在Java中,静态字段通常拥有与整个应用程序相匹配的生命周期。 解决办法:最大限度的减少静态变量的使用;单例模式时,依赖于延迟加载对象而不是立即加载方式。 2、未关闭的资源导致内存泄露 每当创建连接或者打开流时,JVM都会为这些资源分配内存。如果没有关闭连接,会导致持续占有内存。在任意情况下,资源留下的开放连接都会消耗内存,如果我们不处理,就会降低性能,甚至OOM。 解决办法:使用finally块关闭资源;关闭资源的代码,不应该有异常;jdk1.7后,可以使用try-with-resource块。 3、不正确的equals(

AQS源码详细解读

a 夏天 提交于 2020-04-06 18:40:04
AQS源码详细解读 [TOC] 基础 在讲解AQS之前,有几个额外的知识需要了解。知道了这些,才能明白AQS框架中很多代码的道理。 CAS相关知识 通过标识位进行线程挂起的并发编程范式 MPSC队列的实现技巧 欢迎加入技术交流群186233599讨论交流,也欢迎关注笔者公众号:风火说。 <!--more--> CAS相关知识 CAS相关知识具体不表,请百度相关概念 通过标识位进行线程挂起的并发编程范式 一个线程通过一个标识位来表明自己进入挂起状态,那么在该线程将挂起标识位设置为真时,需要再次检查所有的资源条件,而后才能真正的将自己挂起。也就是所谓的二次检查。因为别的线程需要通过挂起标识位来判断是否唤醒挂起线程。而如果别的线程均读取到false条件的挂起标识位值,那么该准备进入挂起状态的线程将不会有线程可以唤醒,所以必须执行二次检查,来防止自己进入一个不会被唤醒的错误状态。 用代码来表达上面的观点就是 //检查周边资源,确认线程需要进入挂起状态 while(checkNeedPark()){ //设置挂起标识位为真 needPark = true; //再次检查 if(checkPark()){ //已经设置好标识位,并且确实需要挂起了。进入挂起状态。别的线程在检测到挂起标识位时就可以尝试唤醒 parkThread(); } else{ //清除挂起标识位,再次尝试。

HashMap的ReHash图解

大城市里の小女人 提交于 2020-04-06 18:26:00
昨天在看redis的hash扩容时提到了与java的hashmap类似,之前一直没有仔细研究过,翻了几篇博客,选了容易理解的一片转载下。 resize方法 void resize ( intnewCapacity ) { Entry [ ] oldTable = table ; intoldCapacity = oldTable . length ; . . . . . . //创建一个新的Hash Table Entry [ ] newTable = new Entry [ newCapacity ] ; //将Old Hash Table上的数据迁移到New Hash Table上 transfer ( newTable ) ; table = newTable ; threshold = ( int ) ( newCapacity * loadFactor ) ; } transfer方法 void transfer ( Entry [ ] newTable ) { Entry [ ] src = table ; intnewCapacity = newTable . length ; //下面这段代码的意思是: // 从OldTable里摘一个元素出来,然后放到NewTable中 for ( int j = 0 ; j < src . length ; j ++ ) {

JVM(java 虚拟机)内存设置

别说谁变了你拦得住时间么 提交于 2020-04-06 18:22:13
一、设置JVM内存设置 1. 设置JVM内存的参数有四个: -Xmx Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定; -Xms Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值; -Xmn Java Heap Young区大小,不熟悉最好保留默认值; -Xss 每个线程的Stack大小,不熟悉最好保留默认值; 2. 如何设置JVM内存分配: (1)当在命令提示符下启动并使用JVM时(只对当前运行的类Test生效): java -Xmx128m -Xms64m -Xmn32m -Xss16m Test (2)当在集成开发环境下(如eclipse)启动并使用JVM时: a. 在eclipse根目录下打开eclipse.ini,默认内容为(这里设置的是运行当前开发工具的JVM内存分配): -vmargs -Xms40m -Xmx256m -vmargs表示以下为虚拟机设置参数,可修改其中的参数值,也可添加-Xmn,-Xss,另外,eclipse.ini内还可以设置非堆内存,如:-XX:PermSize=56m,-XX:MaxPermSize=128m。 此处设置的参数值可以通过以下配置在开发工具的状态栏显示: 在eclipse根目录下创建文件options

Java对象和锁

巧了我就是萌 提交于 2020-04-06 18:04:32
Java对象保存在内存中时,由以下三部分组成: 对象头 实例数据 对齐填充字节 而对象头又由下面几部分组成: Mark Word 指向类的指针 数组长度(只有数组对象才有) 1. Mark Word Mark Word记录了对象和锁有关的信息,当这个对象被synchronized关键字当成同步锁时,围绕这个锁的一系列操作都和Mark Word有关。Mark Word在32位JVM中的长度是32bit,在64位JVM中长度是64bit。 Mark Word在不同的锁状态下存储的内容不同,在32位JVM中是这么存的: 其中无锁和偏向锁的锁标志位都是01,只是在前面的1bit区分了这是无锁状态还是偏向锁状态。Epoch是指偏向锁的时间戳。 JDK1.6以后的版本在处理同步锁时存在锁升级的概念,JVM对于同步锁的处理是从偏向锁开始的,随着竞争越来越激烈,处理方式从偏向锁升级到轻量级锁,最终升级到重量级锁。 JVM一般是这样使用锁和Mark Word的: step1:当没有被当成锁时,这就是一个普通的对象,Mark Word记录对象的HashCode,锁标志位是01,是否偏向锁那一位是0。 step2:当对象被当做同步锁并有一个线程A抢到了锁时,锁标志位还是01,但是否偏向锁那一位改成1,前23bit记录抢到锁的线程id,表示进入偏向锁状态。 step3:当线程A再次试图来获得锁时

python的多线程、多进程、协程用代码详解

醉酒当歌 提交于 2020-04-06 16:39:40
前言 文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。 作者:刘早起早起 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http://t.cn/A6Zvjdun 很多时候我们写了一个爬虫,实现了需求后会发现了很多值得改进的地方,其中很重要的一点就是爬取速度。本文就通过代码讲解如何使用 多进程、多线程、协程 来提升爬取速度。注意:我们不深入介绍理论和原理,一切都在代码中。 同步 首先我们写一个简化的爬虫,对各个功能细分,有意识进行函数式编程。下面代码的目的是访问300次百度页面并返回状态码,其中parse_1函数可以设定循环次数,每次循环将当前循环数(从0开始)和url传入parse_2函数。 性能的消耗主要在IO请求中,当单进程单线程模式下请求URL时必然会引起等待 示例代码就是典型的串行逻辑,parse_1将url和循环数传递给parse_2,parse_2请求并返回状态码后parse_1继续迭代一次,重复之前步骤 多线程 因为CPU在执行程序时每个时间刻度上只会存在一个线程,因此多线程实际上提高了进程的使用率从而提高了CPU的使用率 实现多线程的库有很多,这里用concurrent.futures中的ThreadPoolExecutor来演示

缓存一致性问题

≯℡__Kan透↙ 提交于 2020-04-06 15:05:41
一般我们的热点数据用到缓存,都存在一个问题。 就是在数据更新时,到底是 1,先更新db再更新缓存 2,先更新缓存再更新db 3,更新db前让缓存无效 4,更新db后让缓存无效 1,先更新db再更新缓存的情况 存在一个问题,当对一条数据进行更新时,无法保证前面的线程先执行完 然后下一个线程再执行的情况 可能存在这样一种情况:线程1先更新了db但还没更新缓存,然后线程2更新了db又更新了缓存,然后线程1更新了缓存 这种情况还是比较常发生的,因为两个线程同时执行一个方法,时间上的先后难以保证,运行完此方法的先后。因此不推荐。 2,先更新缓存再更新db 这种存在一个问题,假设线程1更新了缓存,但还没更新db,然后线程2更新了缓存又更新了db,然后线程1再更新db 这样就导致了线程不安全的问题,跟1类似,因此不推荐。 3,更新db前让缓存无效 假设线程1先让缓存失效,还没更新db,此时有大量的线程2,3,4,5去查缓存,没有查到就会直接查数据库,造成缓存穿透问题 因此不推荐。 4,更新db后让缓存无效 线程1更新db后,将缓存无效了,然后再查了一次缓存,线程2更新db后,将缓存无效了, 此时线程1还是旧的数据,这种情况的发生是线程2的写db速度比线程1的读还快,一般这种情况概率比较低 所以推荐这种做法。 来源: oschina 链接: https://my.oschina.net/u

线程共享进程的那些资源?

孤人 提交于 2020-04-06 11:46:07
线程共享进程的那些资源? 线程共享的环境包括: 进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这许多共性的同时,还拥有自己的个性。有了这些个性,线程才能实现并发性。这些个性包括: 1.线程ID 每个线程都有自己的线程ID,这个ID在本进程中是唯一的。进程用此来标识线程。 2.寄存器组的值 由于线程间是并发运行的,每个线程有自己不同的运行线索,当从一个线程切换到另一个线程上时,必须将原有的线程的寄存器集合的状态保存,以便将来该线程在被重新切换到时能得以恢复。 3.线程的栈 栈是保证线程独立运行所必须的。线程函数可以调用函数,而被调用函数中又是可以层层嵌套的,所以线程必须拥有自己的函数堆栈,使得函数调用可以正常执行,不受其他线程的影响。 4.错误返回码 由于同一个进程中有很多个线程在同时运行,可能某个线程进行系统调用后设置了errno值,而在该线程还没有处理这个错误,另外一个线程就在此时被调度器投入运行,这样错误值就有可能被修改。所以,不同的线程应该拥有自己的错误返回码变量。 5.线程的信号屏蔽码 由于每个线程所感兴趣的信号不同,所以线程的信号屏蔽码应该由线程自己管理。但所有的线程都 共享同样的信号处理器。 6.线程的优先级 由于线程需要像进程那样能够被调度