编写多线程的 Java 应用程序.pdf
《编写多线程的 Java 应用程序.pdf》由会员分享,可在线阅读,更多相关《编写多线程的 Java 应用程序.pdf(7页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、编写多线程的编写多线程的 Java 应用程序应用程序 如何避免当前编程中最常见的问题如何避免当前编程中最常见的问题 Alex Roetter(aroetterCS.Stanford.edu)Teton Data Systems 的软件工程师 2001 年 2 月 Java Thread API 允许程序员编写具有多处理机制优点的应用程序 在后台处理任务的同时保持用户所需的交互感Alex Roetter 介绍了 Java Thread API并概述多线程可能引起的问题以及常见问题的解决方案 几乎所有使用 AWT 或 Swing 编写的画图程序都需要多线程但多线程程序会造成许多困难 刚开始编程的开
2、发者常常会发现他们被一些问题所折磨 例如不正确的程序行为或死锁 在本文中我们将探讨使用多线程时遇到的问题并提出那些常见陷阱的解决方案 线程是什么线程是什么 一个程序或进程能够包含多个线程这些线程可以根据程序的代码执行相应的指令多线程看上去似乎在并行执行它们各自的工作就像在一台计算机上运行着多个处理机一样在多处理机计算机上实现多线程时它们确实可以并行工作和进程不同的是线程共享地址空间也就是说多个线程能够读写相同的变量或数据结构 编写多线程程序时你必须注意每个线程是否干扰了其他线程的工作可以将程序看作一个办公室如果不需要共享办公室资源或与其他人交流所有职员就会独立并行地工作某个职员若要和其他人交谈
3、当且仅当该职员在听且他们两说同样的语言此外只有在复印机空闲且处于可用状态没有仅完成一半的复印工作没有纸张阻塞等问题时职员才能够使用它在这篇文章中你将看到在 Java 程序中互相协作的线程就好像是在一个组织良好的机构中工作的职员 在多线程程序中线程可以从准备就绪队列中得到并在可获得的系统 CPU 上运行操作系统可以将线程从处理器移到准备就绪队列或阻塞队列中这种情况可以认为是处理器挂起了该线程同样Java 虚拟机(JVM)也可以控制线程的移动在协作或抢先模型中从准备就绪队列中将进程移到处理器中于是该线程就可以开始执行它的程序代码 协作式线程模型允许线程自己决定什么时候放弃处理器来等待其他的线程 程
4、序开发员可以精确地决定某个线程何时会被其他线程挂起允许它们与对方有效地合作缺点在于某些恶意或是写得不好的线程会消耗所有可获得的 CPU 时间导致其他线程饥饿 在抢占式线程模型中操作系统可以在任何时候打断线程通常会在它运行了一段时间就是所谓的一个时间片后才打断它这样的结果自然是没有线程能够不公平地长时间霸占处理器然而随时可能打断线程就会给程序开发员带来其他麻烦同样使用办公室的例子假设某个职员抢在另一人前使用复印机但打印工作在未完成的时候离开了另一人接着使用复印机时该复印机上可能就还有先前那名职员留下来的资料抢占式线程模型要求线程正确共享资源协作式模型却要求线程共享执行时间由于 JVM 规范并没有
5、特别规定线程模型Java 开发员必须编写可在两种模型上正确运行的程序在了解线程以及线程间通讯的一些方面之后我们可以看到如何为这两种模型设计程序 线程和线程和 Java 语言语言 为了使用 Java 语言创建线程你可以生成一个 Thread 类或其子类的对象并给这个对象发送 start()消息程序可以向任何一个派生自 Runnable 接口的类对象发送 start()消息每个线程动作的定义包含在该线程对象的 run()方法中run 方法就相当于传统程序中的 main()方法线程会持续运行直到 run()返回为止此时该线程便死了 上锁上锁 大多数应用程序要求线程互相通信来同步它们的动作 在 Jav
6、a 程序中最简单实现同步的方法就是上锁 为了防止同时访问共享资源 线程在使用资源的前后可以给该资源上锁和开锁假想给复印机上锁任一时刻只有一个职员拥有钥匙若没有钥匙就不能使用复印机给共享变量上锁就使得 Java 线程能够快速方便地通信和同步某个线程若给一个对象上了锁就可以知道没有其他线程能够访问该对象即使在抢占式模型中其他线程也不能够访问此对象直到上锁的线程被唤醒完成工作并开锁那些试图访问一个上锁对象的线程通常会进入睡眠状态直到上锁的线程开锁一旦锁被打开这些睡眠进程就会被唤醒并移到准备就绪队列中 在 Java 编程中所有的对象都有锁线程可以使用 synchronized 关键字来获得锁在任一时刻
7、对于给定的类的实例方法或同步的代码块只能被一个线程执行这是因为代码在执行之前要求获得对象的锁继续我们关于复印机的比喻为了避免复印冲突我们可以简单地对复印资源实行同步如同下列的代码例子任一时刻只允许一位职员使用复印资源通过使用方法在 Copier 对象中来修改复印机状态这个方法就是同步方法只有一个线程能够执行一个 Copier 对象中同步代码因此那些需要使用 Copier 对象的职员就必须排队等候 class CopyMachine public synchronized void makeCopies(Document d,int nCopies)/only one thread execut
8、es this at a time public void loadPaper()/multiple threads could access this at once!synchronized(this)/only one thread accesses this at a time /feel free to use shared resources,overwrite members,etc.Fine-grain 锁锁 在对象级使用锁通常是一种比较粗糙的方法为什么要将整个对象都上锁而不允许其他线程短暂地使用对象中其他同步方法来访问共享资源如果一个对象拥有多个资源 就不需要只为了让一个线程
9、使用其中一部分资源就将所有线程都锁在外面由于每个对象都有锁可以如下所示使用虚拟对象来上锁 class FineGrainLock MyMemberClass x,y;Object xlock=new Object(),ylock=new Object();public void foo()synchronized(xlock)/access x here /do something here-but dont use shared resources synchronized(ylock)/access y here public void bar()synchronized(this)/ac
10、cess both x and y here /do something here-but dont use shared resources 若为了在方法级上同步不能将整个方法声明为 synchronized 关键字它们使用的是成员锁而不是 synchronized 方法能够获得的对象级锁 信号量信号量 通常情况下可能有多个线程需要访问数目很少的资源假想在服务器上运行着若干个回答客户端请求的线程这些线程需要连接到同一数据库但任一时刻只能获得一定数目的数据库连接 你要怎样才能够有效地将这些固定数目的数据库连接分配给大量的线程一种控制访问一组资源的方法除了简单地上锁之外就是使用众所周知的信号量计
11、数(counting semaphore)信号量计数将一组可获得资源的管理封装起来信号量是在简单上锁的基础上实现的,相当于能令线程安全执行并初始化为可用资源个数的计数器例如我们可以将一个信号量初始化为可获得的数据库连接个数一旦某个线程获得了信号量可获得的数据库连接数减一线程消耗完资源并释放该资源时计数器就会加一当信号量控制的所有资源都已被占用时 若有线程试图访问此信号量 则会进入阻塞状态 直到有可用资源被释放 信号量最常见的用法是解决消费者生产者问题当一个线程进行工作时若另外一个线程访问同一共享变量就可能产生此问题消费者线程只能在生产者线程完成生产后才能够访问数据使用信号量来解决这个问题就需要
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编写多线程的 Java 应用程序 编写 多线程
限制150内