第9讲并发编程
并发编程之CLH同步队列出队入队详解

并发编程之CLH同步队列出队⼊队详解本章重点讲解内容如下:1、什么是CLH同步队列2、为什么需要CLH同步队列3、CLH同步队列原理(即队列如何⼊队、出队)⼀什么是CLH队列AbstractQueuedSynchronizer类⽂件开头,作者Doug Lea⼀⼤篇幅来介绍CLH队列,⼤意如下: CLH队列是⼀个FIFO的双向链表:由head、tail、node中间节点组成,每个Node节点包含:thread、waitStatus、next、pre属性 当线程获取同步状态失败后,会将当前线程构造成⼀个Node节点插⼊链表(如果第⼀次插⼊会初始化head节点为虚拟节点),插⼊链表都是尾部插⼊并且setTail为当前节点,同时会阻塞当前线程(调⽤LockSupport.park⽅法)。
当线程释放同步状态后,会唤醒当前节点的next节点,next节点会抢占同步资源,抢占失败后重新阻塞,成功后next节点会重新setHead为当前线程的节点,将之前的head废弃。
⼆为什么需要CLH队列是为了减少多线程抢占资源造成不必要的cpu上下⽂切换开销。
通过看AQS源码我们知道抢占同步器状态是调⽤pareAndSwapInt⽅法,其实底层就是调⽤的jvm的cas函数。
当多个线程同时在cas的时候,最多只能有⼀个抢占成功,其余的都在⾃旋,这样就造成了不必要的cpu开销。
若引⼊CLH队列队列,⾄于pre执⾏完毕,才唤醒next节点,这样最多只有next节点和新进⼊的线程抢占cpu资源,其余的线程都是阻塞状态,极⼤的减少了不必要的cpu开销。
三 CLH队列原理(如何⼊队、出队)1)⼊队⼊队代码如下:1//获取锁2public final void acquire(int arg) {3//tryAcquire尝试获取锁,Semaphore、coutDownLatch等各个⼯具类实现不⼀致4if (!tryAcquire(arg) &&5//acquireQueued:tryAcquire成功就setHead为当前节点,失败则阻塞当前线程6//addWaiter加⼊同步等待队列7 acquireQueued(addWaiter(Node.EXCLUSIVE), arg))8 selfInterrupt();9 }10//加⼊等待队列11private Node addWaiter(Node mode) {12 Node node = new Node(Thread.currentThread(), mode);13// Try the fast path of enq; backup to full enq on failure14// ⾮⾸次插⼊,可直接setTail15// 设置⽼的tail为当天tail的pre节点16 Node pred = tail;17if (pred != null) {18 node.prev = pred;19if (compareAndSetTail(pred, node)) {20 pred.next = node;21return node;22 }23 }24//⾸次插⼊,需要创建虚拟的head节点25 enq(node);26return node;27 }28private Node enq(final Node node) {29for (;;) {30 Node t = tail;31// 如果 tail 是 null,就创建⼀个虚拟节点,同时指向 head 和 tail,称为初始化。
java处理并发的方法

java处理并发的方法
Java中处理并发的方法主要有以下几种:
1. 使用线程池:线程池是一种管理线程的方式,可以避免线程的创建和销毁的频繁操作,从而提高程序的并发性能。
Java中提供了System.out.println()方法的线程池实现,即System.out.println()方法可以被并发地调用,不会产生竞争条件。
2. 使用锁机制:锁机制可以保障多个线程对共享资源的互斥访问,避免竞争条件和数据不一致的问题。
Java中提供了原子变量和互斥量两种锁的实现方式。
原子变量是一个不可变的数据结构,可以保证多个线程同时访问它的值时不会出现竞争条件;互斥量可以确保多个线程同时访问共享资源时不会同时出现。
3. 使用并发编程模型:Java中的并发编程模型主要是
SMP(Single-Machine Precision)和MP(Multi-Machine Precision)模型,可以处理大规模数据和高并发访问。
SMP模型可以保证在同一台机器上多个线程同时访问相同的共享资源时不会出现竞争条件,而MP模型可以在不同机器上分配不同的计算资源来处理不同方向的计算任务。
4. 使用多路复用技术:多路复用技术可以让一个请求在多个计算任务之间多次转发,从而提高计算效率。
Java中提供了多路复用的实现方式,如Socket多路复用和URL多路复用。
以上是Java中处理并发的一些常见方法,具体应用需要根据具体场景进行选择。
java并发编程的例子

Java 并发编程的例子有很多,以下是几个常见的例子:1. 多线程并发执行任务```javapublic class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行任务"); }}public class Main {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread t1 = new Thread(myRunnable);Thread t2 = new Thread(myRunnable);t1.start();t2.start();}}```2. 使用 synchronized 关键字保证线程安全```javapublic class Counter {private int count;public synchronized void increment() {count++;}public synchronized int getCount() {return count;}}public class Main {public static void main(String[] args) {Counter counter = new Counter();for (int i = 0; i < 1000; i++) {new Thread(() -> {counter.increment();}).start();}System.out.println(counter.getCount()); }}```3. 使用 Lock 接口实现锁机制```javapublic class Counter {private int count;private Lock lock = new ReentrantLock();public void increment() {lock.lock();try {count++;} finally {lock.unlock();}}public int getCount() {lock.lock();try {return count;} finally {lock.unlock();}}}public class Main {public static void main(String[] args) {Counter counter = new Counter();for (int i = 0; i < 1000; i++) {new Thread(() -> {counter.increment();}).start();}System.out.println(counter.getCount()); }}```以上是三个常见的Java 并发编程例子,其中第一个例子是简单的多线程并发执行任务,第二个例子使用 synchronized 关键字保证线程安全,第三个例子使用 Lock 接口实现锁机制。
C#多线程开发:并行、并发与异步编程

C#多线程开发:并⾏、并发与异步编程概述现代程序开发过程中不可避免会使⽤到多线程相关的技术,之所以要使⽤多线程,主要原因或⽬的⼤致有以下⼏个:1、业务特性决定程序就是多任务的,⽐如,⼀边采集数据、⼀边分析数据、同时还要实时显⽰数据;2、在执⾏⼀个较长时间的任务时,不能阻塞UI界⾯响应,必须通过后台线程处理;3、在执⾏批量计算密集型任务时,采⽤多线程技术可以提⾼运⾏效率。
传统使⽤的多线程技术有:1. Thread & ThreadPool2. Timer3. BackgroundWorker⽬前,这些技术都不再推荐使⽤了,⽬前推荐采⽤基于任务的异步编程模型,包括并⾏编程和Task的使⽤。
Concurrency并发和Multi-thread多线程不同你在吃饭的时候,突然来了电话。
1. 你吃完饭再打电话,这既不并发也不多线程2. 你吃⼀⼝饭,再打电话说⼀句话,然后再吃饭,再说⼀句话,这是并发,但不多线程。
3. 你有2个嘴巴。
⼀个嘴巴吃饭,⼀个嘴巴打电话。
这就是多线程,也是并发。
并发:表⽰多个任务同时执⾏。
但是有可能在内核是串⾏执⾏的。
任务被分成了多个时间⽚,不断切换上下⽂执⾏。
多线程:表⽰确实有多个处理内核,可同时处理多个任务。
⼀、并发编程:使⽤ThreadPool轮询并发⽅法是使⽤⼀个List(或其他容器)把所有的对象放进去,创建⼀个线程(为了防⽌UI假死,由于这个线程创建后会⼀直执⾏切运算密集,所以使⽤TheadPool和Thread差别不⼤),在这个线程中使⽤foreach(或for)循环依次对每个对象执⾏ReceiveData⽅法,每次执⾏的时候创建⼀个线程池线程来执⾏。
代码如下:使⽤Task轮询并发⼆、并⾏编程:private static bool IsPrimeNumber(int number){if (number < 1){return false;}if (number == 1 && number == 2){return true;}for (int i = 2; i < number; i++){if (number % i == 0){return false;}}return true;} 如果不采⽤并⾏编程,常规实现⽅法:for (int i = 1; i <= 10000; i++){bool b = IsPrimeNumber(i);Console.WriteLine($"{i}:{b}");}采⽤并⾏编程⽅法Parallel.For(1, 10000, x=>{bool b = IsPrimeNumber(x);Console.WriteLine($"{i}:{b}");})Parallel类还有⼀个ForEach⽅法,使⽤和For类似。
Java并发编程实践-电子书-01章

第一章Java并发编程实践基础第一章Java并发编程实践基础 (1)1.1 进程与线程 (2)1.1.1 进程 (2)1.1.2 线程 (6)1.2 创建多线程 (7)1.2.1 继承Thread 创建线程 (8)1.2.2 实现Runnable 接口创建线程 (8)1.2.3 线程池 (9)1.3 线程的基本控制 (12)1.3.1 使用Sleep 暂停执行 (13)1.3.2 使用join 等待另外一个线程结束 (13)1.3.3 使用中断(Interrupt)取消线程 (15)1.3.4 使用Stop 终止线程 (18)1.3.5 结束程序的执行 (19)1.4 并发编程实践简述 (19)参考文献: (20)1.1进程与线程进程和线程是两个既有关系,又有重大区别的计算机概念,本届首先回顾一下进程和线程的基本概念,然后讲解一下他们的区别,最后是Java 线程概念模型。
1.1.1进程讲解进程的概念时,首先会提到与之相关的另一个概念:程序。
首先介绍程序的概念,然后引入进程。
1.1.1.1程序与资源共享1.程序的封闭性与可再现性在程序设计中,程序员习惯于用顺序方式编制程序。
例如,一个比较典型的顺序程序是:先从某一外部设备(例如磁盘)上输入数据,随之一步一步进行计算,最后将计算结果输出。
计算机中的这种程序活动有如下几个特点:(1)一个程序在机器中运行时独占全机资源,因此除了初始状态外,只有程序本身规定的动作才能改变这些资源的状态。
(2)机器严格地顺序执行程序规定的动作。
每个动作都必须在前一动作结束后才能开始,除了人为干预造成机器暂时停顿外,前一动作的结束就意味着后一动作的开始。
程序和机器执行程序的严格一一对应。
(3)程序的执行结果与它的运行速度无关。
也就是说,处理机在执行程序两个动作之间的停顿不会影响程序的执行结果。
上述特点概况起来就是程序的封闭性和可再现性。
所谓封闭性指的是程序一旦开始运行,其计算结果就只取决于程序本身,除了人为地改变机器的运行状态或机器故障以外,没有其它因素能够对程序的运行过程施加影响。
concurrent programming in java 中文

concurrent programming in java 中文Concurrent programming in Java(Java中的并发编程)引言:在当今的软件开发领域中,多核处理器的普及使得并发编程成为了必不可少的技能。
并发编程可以最大程度地利用计算机的资源,提高系统的性能和响应速度。
Java作为一种广泛使用的编程语言,提供了强大的多线程支持,使开发者能够轻松地进行并发编程。
本文将深入探讨Java中的并发编程,并详细介绍如何利用Java中的工具和技术实现并发编程。
第一步:理解并发编程的概念和原理(200字左右)并发编程是指同时执行多个独立的任务的编程方式。
在传统的串行编程中,程序按照单一的控制流逐一执行,而并发编程则允许多个任务同时执行。
并发编程的目标是提高系统的吞吐量、性能和响应速度。
第二步:了解Java中的线程(200字左右)Java提供了Thread类来实现多线程编程。
线程是程序的基本执行单元,一个Java程序可以同时运行多个线程。
通过继承Thread类并重写run方法,可以创建自己的线程,并通过start方法启动线程的执行。
第三步:学习Java中的同步机制(300字左右)在并发编程中,线程之间共享数据可能导致竞态条件(Race Condition)和其他线程安全问题。
为了解决这些问题,Java提供了多种同步机制。
其中最常用的是synchronized关键字和Lock接口。
synchronized关键字用于修饰方法或代码块,确保同一时刻只有一个线程执行该段代码。
Lock 接口提供了更灵活的同步机制,可以实现更加复杂的线程同步。
第四步:熟悉Java中的线程间通信(300字左右)线程间通信是并发编程中非常重要的一个概念。
Java提供了多种线程间通信的机制,如wait方法和notify方法。
wait方法用于使线程等待某个条件满足,而notify方法用于唤醒一个等待中的线程。
通过这些机制,多个线程可以协调执行,实现数据的共享和同步。
《C语言程序设计》教案(清华谭浩强)
《C语言程序设计》教案(清华谭浩强)第一章:C语言概述1.1 课程介绍介绍C语言的历史和发展解释C语言的特点和应用范围强调学习C语言的重要性和目的1.2 C语言的基本概念解释编程语言和编译器的概念介绍C语言的基本数据类型和变量讲解C语言的语法结构和程序结构1.3 C语言的编译过程解释编译器的角色和功能介绍编译过程中的预处理、编译、汇编和步骤强调编译过程中产生的文件和它们的作用第二章:基本数据类型和运算符2.1 基本数据类型介绍整型、浮点型、字符型和布尔型的概念和用法解释不同数据类型的存储方式和大小强调数据类型的选择和使用场景2.2 变量和常量解释变量的概念和作用介绍变量的声明和初始化方法讲解常量的概念和用法2.3 运算符介绍算术运算符、关系运算符和逻辑运算符的概念和用法解释赋值运算符和条件运算符的作用强调不同运算符的优先级和使用规则第三章:控制语句3.1 条件语句介绍if语句的语法和用法讲解switch语句的概念和用法强调条件语句的选择和嵌套使用3.2 循环语句介绍for循环、while循环和do-while循环的概念和用法解释循环控制语句如break和continue的作用强调循环条件的设置和循环次数的控制3.3 跳转语句介绍goto语句的概念和用法讲解label标签的作用和跳转规则强调跳转语句的使用场景和可能导致的问题第四章:函数和指针4.1 函数的基本概念介绍函数的定义和声明讲解函数的参数传递和返回值强调函数的命名规则和命名规范4.2 指针的概念和用法解释指针的概念和作用介绍指针的声明和初始化方法讲解指针的赋值和指针运算4.3 指针和数组介绍数组的概念和用法解释指针和数组的关系强调指针在数组操作中的应用第五章:结构体和文件操作5.1 结构体的概念和用法介绍结构体的定义和声明讲解结构体的成员访问和内存布局强调结构体在数据组织中的应用5.2 文件操作的基本概念解释文件的概念和文件操作的重要性介绍文件打开、读写、关闭等操作的方法强调文件操作中的错误处理和文件指针的管理第六章:动态内存分配6.1 动态内存分配的概念介绍动态内存分配的原因和必要性解释malloc、calloc和realloc函数的作用和用法强调动态内存分配的注意事项和错误处理6.2 链表的概念和用法介绍链表的定义和结构讲解链表的创建、插入、删除和遍历操作强调链表的优势和应用场景6.3 动态内存分配的应用实例通过实例演示动态内存分配在实际编程中的应用讲解内存泄漏和内存溢出的概念强调编写高效和安全的程序的重要性第七章:字符串处理7.1 字符串的基本概念介绍字符串的定义和表示方法解释字符串的长度和字符串的结束标志强调字符串与数组的区别和联系7.2 字符串的常用函数介绍字符串的输入输出函数如printf和scanf 讲解字符串的拷贝、连接、比较等操作函数强调字符串处理函数的使用和注意事项7.3 字符串处理的应用实例通过实例演示字符串处理在实际编程中的应用讲解字符串排序、查找和替换等操作强调字符串处理在文本分析和数据处理中的应用第八章:标准库函数8.1 标准输入输出库函数介绍标准输入输出库stdio.h中的常用函数讲解文件读写、数据转换等函数的用法和功能强调标准库函数的使用场景和注意事项8.2 字符串处理库函数介绍字符串处理库string.h中的常用函数讲解字符串比较、查找和替换等函数的用法和功能强调字符串处理库函数的使用和与其他库函数的配合8.3 数学计算库函数介绍数学计算库math.h中的常用函数讲解数学运算、三角函数和指数函数等函数的用法和功能强调数学计算库函数在数学计算和科学计算中的应用第九章:并发编程和同步机制9.1 并发编程的基本概念介绍并发编程的定义和目的解释进程和线程的概念和关系强调并发编程的优势和挑战9.2 并发编程的同步机制介绍互斥锁、条件变量和信号量等同步机制的原理和用法讲解同步机制在多线程编程中的应用和注意事项强调同步机制在避免竞态条件和数据一致性中的重要性9.3 并发编程的应用实例通过实例演示并发编程在实际应用中的优势和挑战讲解多线程的创建、同步和通信等操作强调并发编程在多任务处理和性能优化中的应用第十章:C语言编程实践10.1 编程实践的重要性强调编程实践在学习和掌握C语言中的重要性解释编程实践对于提高编程能力和解决问题的作用强调编程实践中的代码质量和编程规范10.2 编程实践的项目和案例介绍常见的编程实践项目和案例讲解实际编程中的问题解决方法和技巧强调编程实践中的调试和测试的重要性10.3 编程实践的资源和工具介绍编程实践中的常用工具和环境讲解集成开发环境(IDE)的使用和代码管理强调编程实践中的团队合作和代码分享的重要性重点和难点解析重点环节1:C语言的基本概念和特点需要重点关注C语言的历史和发展,以及其特点和应用范围。
实战Java高并发程序设计
4.2 Java 虚拟机对锁优化所做的努力 146 4.2.1 锁偏向 146 4.2.2 轻量级锁 146 4.2.3 自旋锁 146 4.2.4 锁消除 146
3.1 多线程的团队协作:同步控制 70 3.1.1 synchronized 的功能扩展:重入锁 71 3.1.2 重入锁的好搭档:Condition 条件 80 3.1.3 允许多个线程同时访问:信号量(Semaphore) 83 3.1.4 ReadWriteLock 读写锁 85 3.1.5 倒计时器:CountDownLatch 87 3.1.6 循环栅栏:CyclicBarrier 89 3.1.7 线程阻塞工具类:LockSupport 92
3.2 线程复用:线程池 95 3.2.1 什么是线程池 96 3.2.2 不要重复发明轮子:JDK 对线程池的支持 97 3.2.3 刨根究底:核心线程池的内部实现 102 3.2.4 超负载了怎么办:拒绝策略 106 3.2.5 自定义线程创建:ThreadFactory 109 3.2.6 我的应用我做主:扩展线程池 110 3.2.7 合理的选择:优化线程池线程数量 112 3.2.8 堆栈去哪里了:在线程池中寻找堆栈 113 3.2.9 分而治之:Fork/Join 框架 117
V
1.3.5 无等待(Wait-Free) 13 1.4 有关并行的两个重要定律 13
1.4.1 Amdahl 定律 13 1.4.2 Gustafson 定律 16 1.4.3 Amdahl 定律和 Gustafson 定律是否相互矛盾 16 1.5 回到 Java:JMM 17 1.5.1 原子性(Atomicity) 18 1.5.2 可见性(Visibility) 20 1.5.3 有序性(Ordering) 22 1.5.4 哪些指令不能重排:Happen-Before 规则 27 1.6 参考文献 27 第 2 章 Java 并行程序基础 ..............................................................................................................................29 2.1 有关线程你必须知道的事 29 2.2 初始线程:线程的基本操作 32 2.2.1 新建线程 32 2.2.2 终止线程 34 2.2.3 线程中断 38 2.2.4 等待(wait)和通知(notify) 41 2.2.5 挂起(suspend)和继续执行(resume)线程 44 2.2.6 等待线程结束(join)和谦让(yield) 48 2.3 volatile 与 Java 内存模型(JMM)50 2.4 分门别类的管理:线程组 52 2.5 驻守后台:守护线程(Daemon) 54 2.6 先干重要的事:线程优先级 55 2.7 线程安全的概念与 synchronized 57
Java并发编程ArrayBlockingQueue的实现
Java并发编程ArrayBlockingQueue的实现⼀、简介ArrayBlockingQueue 顾名思义:基于数组的阻塞队列。
数组是要指定长度的,所以使⽤ ArrayBlockingQueue 时必须指定长度,也就是它是⼀个有界队列。
它实现了 BlockingQueue 接⼝,有着队列、集合以及阻塞队列的所有⽅法。
ArrayBlockingQueue 是线程安全的,内部使⽤ ReentrantLock 来保证。
ArrayBlockingQueue ⽀持对⽣产者线程和消费者线程进⾏公平的调度。
当然默认情况下是不保证公平性的,因为公平性通常会降低吞吐量,但是可以减少可变性和避免线程饥饿问题。
⼆、数据结构通常,队列的实现⽅式有数组和链表两种⽅式。
对于数组这种实现⽅式来说,我们可以通过维护⼀个队尾指针,使得在⼊队的时候可以在 O(1)O(1) 的时间内完成;但是对于出队操作,在删除队头元素之后,必须将数组中的所有元素都往前移动⼀个位置,这个操作的复杂度达到了 O(n)O(n),效果并不是很好。
如下图所⽰:为了解决这个问题,我们可以使⽤另外⼀种逻辑结构来处理数组中各个位置之间的关系。
假设现在我们有⼀个数组 A[1…n],我们可以把它想象成⼀个环型结构,即 A[n] 之后是 A[1],相信了解过⼀致性 Hash 算法的童鞋应该很容易能够理解。
如下图所⽰:我们可以使⽤两个指针,分别维护队头和队尾两个位置,使⼊队和出队操作都可以在 O(1O(1 )的时间内完成。
当然,这个环形结构只是逻辑上的结构,实际的物理结构还是⼀个普通的数组。
讲完 ArrayBlockingQueue 的数据结构,接下来我们从源码层⾯看看它是如何实现阻塞的。
三、源码分析3.1 属性// 队列的底层结构final Object[] items;// 队头指针int takeIndex;// 队尾指针int putIndex;// 队列中的元素个数int count;final ReentrantLock lock;// 并发时的两种状态private final Condition notEmpty;private final Condition notFull;items 是⼀个数组,⽤来存放⼊队的数据;count 表⽰队列中元素的个数;takeIndex 和 putIndex 分别代表队头和队尾指针。
Java并发编程之概念一:并行与并发
Java并发编程之概念⼀:并⾏与并发概念解释并⾏性和并发性是既相似⼜有区别的两个概念。
并⾏性是指两个或多个事件在同⼀时刻发⽣。
⽽并发性是指连个或多个事件在同⼀时间间隔内发⽣。
在多道程序环境下,并发性是指在⼀段时间内宏观上有多个程序在同时运⾏,但在单处理机环境下(⼀个处理器),每⼀时刻却仅能有⼀道程序执⾏,故微观上这些程序只能是分时地交替执⾏。
例如,在1秒钟时间内,0-15ms程序A运⾏;15-30ms程序B运⾏;30-45ms程序C运⾏;45-60ms程序D运⾏,因此可以说,在1秒钟时间间隔内,宏观上有四道程序在同时运⾏,但微观上,程序A、B、C、D是分时地交替执⾏的。
操作系统并发程序执⾏的特点:1. 并发环境下,由于程序的封闭性被打破,出现了新的特点:①程序与计算不再⼀⼀对应,⼀个程序副本可以有多个计算2. 并发程序之间有相互制约关系,直接制约体现为⼀个程序需要另⼀个程序的计算结果,间接制约体现为多个程序竞争某⼀资源,如处理机、缓冲区等。
3. 并发程序在执⾏中是⾛⾛停停,断续推进的并发和并⾏的作⽤ 通过并发和并⾏能够使得应⽤程序可以充分利⽤多核以及GPU的计算能⼒,从⽽提⾼应⽤程序的性能,⽐如在以下⼏个⽅⾯中:1. 使⽤异步I/O操作可以提⾼应⽤程序的响应性。
⼤多数的GUI应⽤程序都是⽤单个线程来控制所有UI界⾯的更新。
UI线程不应该被占⽤过长时间,不然UI界⾯就会失去对⽤户的响应。
2. 跨多线程的并⾏⼯作可以更好的利⽤系统的资源。
具有多CPU和GPU的现代计算机,通过并⾏可以指数级的提⾼CPU计算受限的应⽤程序的性能。
3. 同时执⾏多个I/O操作(如同时从多个⽹站上获取信息)可以提⾼总体的吞吐量(throughput),等待I/O相应的操作可以⽤来发起新的操作,或者是处理操作返回的结果。
并⾏和并发区别区别⼀:并发是指⼀个处理器同时处理多个任务。
并⾏是指多个处理器或者是多核的处理器同时处理多个不同的任务。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2
Process and Portfolio Management
© 2005 IBM Corporation
线程状态
新建 可运行 运行 阻塞 中止
3
Process and Portfolio Management
© 2005 IBM Corporation
创建可执行线程
创建一个新的可执行线程有两种方式 一种是创建ng.Thread类的子类,这个子类应该 覆写(override)Thread类的run()方法,这样,子类 的实例通过调用start()方法执行线程,JVM调用run()方 法,结果是两个线程并发运行:当前主线程(start()方 法返回的线程)和另一个执行run()方法的线程 另外一种创建线程的方式是实现ng.Runnable接 口,实现类必须实现run()方法。当创建并运行线程 时,实现类的实例作为参数传递给Thread类的构造函 数,然后调用Thread类的start()方法
yield()方法将使正在执行的线程放进可运行缓冲池(从运行状态 进入可运行状态)
休眠(sleep),使线程停止执行一段时间,该时间由你 给定的毫秒数决定
sleep()方法是静态方法,它只是暂停当前执行中的线程,因此 不 能使用sleep()方法来暂停其他线程的执行 当一个线程(a) “睡眠”时,其他线程可以通过调用a.interrupt()来 打断a的“睡眠”,当a的“睡眠”被打断时将抛出异常 InterruptedException
7
Process and Portfolio Management
© 2005 IBM Corporation
线程的调度(cont.)
让步(yield),你的工作已经做得差不多了,可以让别 的线程使用处理器了。不过这只是一个暗示,没有任何 机制保证它将会被采纳。一般来说yield()方法并不常用
10
Process and Portfolio Management
© 2005 IBM Corporation
同步(cont.)
同步方法(普通方法、静态方法)
public synchronized void oper() { //在当前对象上加锁,同一时刻只能有一个线程访问当前对象 的 此方法 }
同步(cont.)
同步控制块(Synchronized Block)
synchronized(syncObject) { //在对象syncObject上加锁,同一时刻只能有一个线程访问 }
12
Process and Portfolio Management
© 2005 IBM Corporation
public static synchronized void oper() {
//在Class对象上加锁,同一时刻只能有一个线程访问此静态方 法 }
AccountDemo.java AccountDemo.java
11 Process and Portfolio Management © 2005 IBM Corporation
TestYield.java, , TestSleep.java TestYield.java TestSleep.java
© 2005 IBM Corporation
8
Process and Portfolio Management
线程的调度(cont.)
优先权(priority),能告诉调度程序当前线程的重要 性如何 加入到某个线程(join),一个线程可以在其它线程之 上调用join()方法,其效果是等待一段时间直到第二个 线程结束才继续执行。如果某个线程在另一个线程t上 调用t.join(),此线程将被挂起,直到目标线程t结束才 恢复
RunnableDemo.java , ThreadDemo.java RunnableDemo.java , ThreadDemo.java
4 Process and Portfolio Management © 2005 IBM Corporation
启动线程
直接调用run()方法而不是start()方法将作为一个普通的 方法运行,但不能开启一个新的线程 多次启动一个线程是非法的,一个线程在完全执行完毕前 不能重新启动
15
Process and Portfolio Management
© 2005 IBM Corporation
使用多线程带来的优势
利用多线程,能够最大限度的利用CPU,因为空闲的时 间被限制在最小,这在Java操作的交互网络环境下显得 非常重要,因为此时空闲时间(比如进行IO处理时)是普 遍存在的 在传统的单线程环境下,程序必须等待这些任务都执行 完才能进行下一个任务,而任由CPU在大多数时候是空 闲的.如果使用多线程,就可以利用空闲时间了 尤其是随着硬件的发展,多CPU,甚至是多核CPU的硬 件系统已经普及,我们使用Java提供的多线程机制就可 以快速方便的编写多线程的应用程序,从而充分利用硬 件资源,提供系统的吞吐率
TestPriority.java , TestJoin.java TestPriority.java , TestJoin.java
9 Process and Portfolio Management © 2005 IBM Corporation
同步
锁定任何对象所占用的内存,使得同一时刻只能有一个 线程在使用它。这是通过 synchronized 关键字来实现 的
死锁问题
如果有多个线程会同时竟争多个共享资源,并且加锁的 顺序不固定,那就有可能出现死锁 程序有死锁的潜在bug,比较难调试出来,所以得小心
ห้องสมุดไป่ตู้
13
Process and Portfolio Management
© 2005 IBM Corporation
线程间的协作
线程可以在已经持有其锁的对象上调用wait()方法(有多 个重载的方法),从而自动释放持有的锁,然后进入此对 象的等待区休眠 线程一旦在某个对象的等待区休眠了,如果休眠时间未 到,那么必须有其它线程在此对象上调用notify()方法或 notifyAll()方法,线程接受到通报后才回醒过来从新竞 争对象的锁 线程可以在已经持有其锁的对象上调用notifyAll()方法 唤醒所有在此对象的等待区休眠的线程 线程可以在已经持有其锁的对象上调用notify()方法在此 对象的等待区休眠的某个线程(到底唤醒谁是不确定的)
6
Process and Portfolio Management
© 2005 IBM Corporation
线程的调度
一个线程对象的start()方法只能被执行一次 线程是抢先式的:优先级 一个时刻只有一个线程在运行 运行到不再是可运行的,或另一个更高优先级的线程成为 可运行 所有可运行线程按优先级保存在缓冲池中
5
Process and Portfolio Management
© 2005 IBM Corporation
继承Thread和实现Runnable的区别
继承Thread实现的多线程,无法实现多个线程操纵同一 个对象,实现Runnable接口的多线程,可以实现多个线 程操纵同一个对象 Java是单继承,继承Thread类将无法再继承其它的类, 实现Runnable 接口则没有此问题
14 Process and Portfolio Management © 2005 IBM Corporation
线程间的协作(cont.)
通过调用wait()方法让某个线程休眠和通过调用notify() 方法或nofifyAll()方法唤醒某些线程的方式称为等待- 唤醒机制 使用等待-唤醒机制往往比调用sleep()方法的轮询机 制效果好,能合理利用CPU资源 注意,要在某个对象上调用wait(),notify()和notifyAll 方法,必须是调用线程已经给此对象加了锁,否则会抛 出IllegalMonitorStateException
第九讲
并发编程
1
Process and Portfolio Management
© 2005 IBM Corporation
概述
把一个问题切分成多个可独立运行的部分,从而提高程序的 响应能力 在程序中,这些彼此独立运行的部分称之为线程(thread) JVM允许应用程序并发运行多个线程
16 Process and Portfolio Management © 2005 IBM Corporation