多线程

多线程-读写锁

懵懂的女人 提交于 2020-03-06 09:00:35
1. 读写锁 ReadWriteLock管理一组锁,一个是只读的锁,一个是写锁。 Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性 假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写(译者注:也就是说:读-读能共存,读-写不能共存,写-写不能共存)。这就需要一个读/写锁来解决这个问题。 对于lock的读写锁,可以通过new ReentrantReadWriteLock()获取到一个读写锁。所谓读写锁,便是多线程之间读不互斥,读写互斥。读写锁是一种自旋锁,如果当前没有读者,也没有写者,那么写者可以立刻获得锁,否则它必须自旋在那里,直到没有任何写者或读者。如果当前没有写者,那么读者可以立即获得该读写锁,否则读者必须自旋在那里,直到写者释放该锁 简单来说就是 独占锁(写锁):一次只能被一个线程占有 共享锁(读锁):该锁可以被多个线程占有! 先看一下没有锁的情况 package demo.ReadWriteLock; ​ import java.util.HashMap; import java.util.Map; ​

Linux内核多线程(一)

孤者浪人 提交于 2020-03-06 08:14:05
Linux内核可以看作一个服务进程(管理软硬件资源,响应用户进程的种种合理以及不合理的请求)。内核需要多个执行流并行,为了防止可能的阻塞,支持多线程是必要的。内核线程就是内核的分身,一个分身可以处理一件特定事情。内核线程的调度由内核负责,一个内核线程处于阻塞状态时不影响其他的内核线程,因为其是调度的基本单位。这与用户线程是不一样的。因为内核线程只运行在内核态,因此,它只能使用大于PAGE_OFFSET(3G)的地址空间。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为NULL;它只在 内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占。 内核线程(thread)或叫守护进程(daemon),在操作系统中占据相当大的比例,当Linux操作系统启动以后,你可以用”ps -ef”命令查看系统中的进程,这时会发现很多以”d”结尾的进程名,确切说名称显示里面加 "[]"的,这些进程就是内核线程。 创建内核线程最基本的两个接口函数是: kthread_run (threadfn, data, namefmt, ...) 和 kernel_thread (int(* fn)(void *),void * arg,unsigned long flags) 这里我们主要介绍kthread_run,后面会专门分析这两个函数的异同。

Java第十次作业--多线程

我的梦境 提交于 2020-03-06 00:51:55
Java第十次作业--多线程 (一)学习总结 1 . 用思维导图对java多线程的学习内容进行总结。 2.阅读程序,采用实现Runnable接口的方式用多线程实现这个小游戏 package test; class Tortoise implements Runnable { private int totalStep; private int tortoiseStep = 0; public Tortoise(int totalStep) { this.totalStep = totalStep; } public void run() { running(); } private synchronized void running() { System.out.println("龟兔赛跑开始了..."); while (tortoiseStep < totalStep) { tortoiseStep++; System.out.println("乌龟跑了" + tortoiseStep + "步..."); } } } class Hare implements Runnable { private int totalStep; private int hareStep = 0; public Hare(int totalStep) { this.totalStep =

java多线程(八)-死锁问题和java多线程总结

十年热恋 提交于 2020-03-06 00:46:09
为了防止对共享受限资源的争夺,我们可以通过synchronized等方式来加锁,这个时候该线程就处于阻塞状态,设想这样一种情况,线程A等着线程B完成后才能执行,而线程B又等着线程C,而线程C又等着线程A。这三个任务之间相互循环等待,但是其实没有哪个任务能够执行,这种情况就发生了死锁。 有一个经典的哲学家就餐问题,可以更清晰的理解死锁问题。有N个哲学家围绕在一张圆形餐桌前,餐桌中间有一份面条,每个哲学家都只有一根筷子,放在他的左手边。(因为餐桌是圆形的,所以就是每两个哲学家之间有一根筷子),所以共计有N个哲学家,N个筷子, 哲学们家们有时候思考,思考时不需要获取其他共享资源;有时候吃面条,吃面条时需要两根筷子,哲学家需要先拿到他right手边的筷子,然后再去拿left手边的筷子。如果此时,left手边筷子不在桌子上(被边上的哲学家拿走了)。则哲学家就把right手边的筷子拿在手中等待。 (调用wait).等待left边的筷子被放下。如果哲学家吃完面条,则放下两根筷子 ,继续思考。 我们仅仅通过逻辑思考,就可以想到如果每个哲学家都拿到了他right手边的筷子,那么此时就发生了死锁,因为实际上桌子上,每个哲学家正好拿到了一根筷子,都在等待他left手边的筷子被放下,但是不会再有筷子被放下了. 代码demo:src\thread_runnable

多线程基础

廉价感情. 提交于 2020-03-06 00:15:12
一、线程和进程的区别: 进程是系统分配资源的最小单位,线程是系统调度的最小单位。 每个进程至少有一个线程存在,即主线程。 进程是有自己的独立地址空间的,有进程控制块(PCB)来控制进程的状态变换,也有专门的算法来控制进程的调度(先进先出,高优先比优先,短作业优先,时间片轮转等),线程是共享进程的资源的,JVM会为每一个线程划分特殊的空间: 二、并发和并行 并发: 多个进程在一个CPU下采用时间片轮转的方式,在一段时间之内,让多个进程都得以推进,称之为并发。(也就是同一时间只有一个进程在执行) 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行 三、线程创建的方法 1.通过继承Thread类 2.实现Runnable接口 3.其他变形 四、线程常见属性 ID 是线程的唯一标识,不同线程不会重复 名称是各种调试工具用到 状态表示线程当前所处的一个情况,下面我们会进一步说明 优先级高的线程理论上来说更容易被调度到 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。 是否存活,即简单的理解,为 run 方法是否运行结束了 线程的中断问题,下面我们进一步说明 五、start()和run()方法 复写run()方法是提供给线程要做的事情的指令清单,而start()方法则是线程真正独立的去执行了 六、中断一个线程 1.调用.thread(

如何创建不可变(Immutable)的Java类或对象

一曲冷凌霜 提交于 2020-03-05 22:58:50
不可变对象(immutable objects),后面文章我将使用immutable objects来代替不可变对象! 那么什么是immutable objects?什么又是mutable Objects呢? immutable Objects就是那些一旦被创建,它们的状态就不能被改变的Objects,每次对他们的改变都是产生了新的immutable的对象,而mutable Objects就是那些创建后,状态可以被改变的Objects. 举个例子:String和StringBuilder,String是immutable的,每次对于String对象的修改都将产生一个新的String对象,而原来的对象保持不变,而StringBuilder是mutable,因为每次对于它的对象的修改都作用于该对象本身,并没有产生新的对象。 但有的时候String的immutable特性也会引起安全问题,这就是 密码应该存放在字符数组中而不是String中 的原因! immutable objects 比传统的mutable对象在多线程应用中更具有优势,它不仅能够保证对象的状态不被改变,而且还可以不使用锁机制就能被其他线程共享。 实际上JDK本身就自带了一些immutable类,比如String,Integer以及其他包装类。为什么说String是immutable的呢?比如:java.lang

Java多线程与JUC——04控制线程

北慕城南 提交于 2020-03-05 21:46:41
Java的线程支持提供了一些工具方法,通过这些方法可以很好地控制线程的执行。 Join线程 Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并发执行变为串行执行。具体看代码: public class ThreadTest1 { /** * join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代码的意思就是: * 程序在 main 线程中调用t1线程的join方法,则main线程放弃cpu控制权,并返回t1线程继续执行直到线程t1执行完毕 * 所以结果是t1线程执行完后,才到主线程执行,相当于在main线程中同步t1线程,t1执行完了,main线程才有执行的机会 */ public static void main ( String [ ] args ) { //main方法是jvm进程的默认的主线程 System . out . println ( "主线程的名字:" + Thread . currentThread ( ) . getName ( ) ) ; //在main线程中创建一个新的线程,并且启动 Thread t1 = new MyThread ( "子线程1" ) ; t1 . start ( ) ; try { //调用了 t1 的 join() 方法,他会将“主线程”给挂起来,使主线程堵塞,让子线程 t1 继续执行, //当

多线程求和,记一个 synchronized 的错误使用方式

孤街醉人 提交于 2020-03-05 20:08:40
  总结:   1. 如果在单线程环境下,几个操作共享变量的方法存在数据依赖关系,那么多线程环境下它们必须是一组原子操作,且与任何修改共享变量的方法互斥。与读方法是否互斥需要看程序的设计,比如 CopyOnWrite 模式下,这些原子操作不会与读共享变量的动作互斥,可以提高读的效率,但缺点是不能保证读操作每次读到的都是最新的值。   2. 保证多线程任务的正确性,是基于各线程对共享变量访问的正确性来保证的。   3. 我们还必须保证,多线程环境下存在数据依赖或控制依赖的方法,操作结果对其它线程的可见性以及操作对其它线程来说的有序性。happen-before 原则便是基于这两点的。   4. 尤其要注意单线程情况下不存在数据依赖,但与其它线程的执行有关的动作。因为单线程下不存在数据依赖,编译器很可能会进行乱序执行。比如修改共享变量并唤醒其它线程,单线程下这两个动作是不存在数据依赖的,如何乱序执行都不会影响单线程下的执行结果。但多线程环境下,被唤醒的线程可能是需要依据共享变量的值工作的,这两个动作在多线程环境下实际是存在数据依赖的。   题目很简单,使用多线程求一亿个数的和。这篇文章主要是为了总结一下多线程编程的思路,保证多线程任务的正确性,是基于各线程对共享变量访问的安全性来保证的。   定义共享数据: public class ArraySource { //源数组

python多线程使用

耗尽温柔 提交于 2020-03-05 16:55:42
python多线程:先举个例子 #coding=utf-8 import threading from time import ctime,sleep def music(func): for i in range(2): print "I was listening to %s. %s" %(func,ctime()) sleep(1) def move(func): for i in range(2): print "I was at the %s! %s" %(func,ctime()) sleep(5) threads = [] t1 = threading.Thread(target=music,args=(u'爱情买卖',)) threads.append(t1) t2 = threading.Thread(target=move,args=(u'阿凡达',)) threads.append(t2) if __name__ == '__main__': for t in threads: t.setDaemon(True) t.start() t.join() print "all over %s" %ctime()    import threading 首先导入threading 模块,这是使用多线程的前提。 threads = [] t1 = threading

几种网络服务器模型的介绍与比较

五迷三道 提交于 2020-03-05 16:52:59
原文链接 前言 事件驱动为广大的程序员所熟悉,其最为人津津乐道的是在图形化界面编程中的应用;事实上,在网络编程中事件驱动也被广泛使用,并大规模部署在高连接数高吞吐量的服务器程序中,如 http 服务器程序、ftp 服务器程序等。相比于传统的网络编程方式,事件驱动能够极大的降低资源占用,增大服务接待能力,并提高网络传输效率。 关于本文提及的服务器模型,搜索网络可以查阅到很多的实现代码,所以,本文将不拘泥于源代码的陈列与分析,而侧重模型的介绍和比较。使用 libev 事件驱动库的服务器模型将给出实现代码。 本文涉及到线程 / 时间图例,只为表明线程在各个 IO 上确实存在阻塞时延,但并不保证时延比例的正确性和 IO 执行先后的正确性;另外,本文所提及到的接口也只是笔者熟悉的 Unix/Linux 接口,并未推荐 Windows 接口,读者可以自行查阅对应的 Windows 接口。 阻塞型的网络编程接口 几乎所有的程序员第一次接触到的网络编程都是从 listen()、send()、recv() 等接口开始的。使用这些接口可以很方便的构建服务器 / 客户机的模型。 我们假设希望建立一个简单的服务器程序,实现向单个客户机提供类似于“一问一答”的内容服务。 图 1. 简单的一问一答的服务器 / 客户机模型 我们注意到,大部分的 socket 接口都是阻塞型的。所谓阻塞型接口是指系统调用(一般是