编写多线程Java应用程序常见问题

几乎所有使用AWT或Swing编写的画图程序都需要多线程。但多线程程序会造成许多困难,刚开始编程的开发者常常会发现他们被一些问题所折磨,例如不正确的程序行为或死锁。

在本文中,我们将探讨使用多线程时遇到的问题,并提出那些常见陷阱的解决方案。

线程是什么?

一个程序或进程能够包含多个线程,这些线程可以根据程序的代码执行相应的指令。多线程看上去似乎在并行执行它们各自的工作,就像在一台计算机上运行着多个处理机一样。在多处理机计算机上实现多线程时,它们确实可以并行工作。和进程不同的是,线程共享地址空间。也就是说,多个线程能够读写相同的变量或数据结构。

编写多线程程序时,你必须注意每个线程是否干扰了其他线程的工作。可以将程序看作一个办公室,如果不需要共享办公室资源或与其他人交流,所有职员就会独立并行地工作。某个职员若要和其他人交谈,当且仅当该职员在“听”且他们两说同样的语言。此外,只有在复印机空闲且处于可用状态(没有仅完成一半的复印工作,没有纸张阻塞等问题)时,职员才能够使用它。在这篇文章中你将看到,在 Java 程序中互相协作的线程就好像是在一个组织良好的机构中工作的职员。

在多线程程序中,线程可以从准备就绪队列中得到,并在可获得的系统 CPU 上运行。操作系统可以将线程从处理器移到准备就绪队列或阻塞队列中,这种情况可以认为是处理器“挂起”了该线程。同样,Java 虚拟机 (JVM) 也可以控制线程的移动在协作或抢先模型中从准备就绪队列中将进程移到处理器中,于是该线程就可以开始执行它的程序代码。

协作式线程模型允许线程自己决定什么时候放弃处理器来等待其他的线程。程序开发员可以精确地决定某个线程何时会被其他线程挂起,允许它们与对方有效地合作。缺点在于某些恶意或是写得不好的线程会消耗所有可获得的 CPU 时间,导致其他线程“饥饿”。

在抢占式线程模型中,操作系统可以在任何时候打断线程。通常会在它运行了一段时间(就是所谓的一个时间片)后才打断它。这样的结果自然是没有线程能够不公平地长时间霸占处理器。然而,随时可能打断线程就会给程序开发员带来其他麻烦。同样使用办公室的例子,假设某个职员抢在另一人前使用复印机,但打印工作在未完成的时候离开了,另一人接着使用复印机时,该复印机上可能就还有先前那名职员留下来的资料。抢占式线程模型要求线程正确共享资源,协作式模型却要求线程共享执行时间。由于 JVM 规范并没有特别规定线程模型,Java 开发员必须编写可在两种模型上正确运行的程序。在了解线程以及线程间通讯的一些方面之后,我们可以看到如何为这两种模型设计程序。

线程和 Java 语言

为了使用 Java 语言创建线程,你可以生成一个 Thread 类(或其子类)的对象,并给这个对象发送 start() 消息。(程序可以向任何一个派生自 Runnable 接口的类对象发送 start() 消息。)每个线程动作的定义包含在该线程对象的 run() 方法中。run 方法就相当于传统程序中的 main() 方法;线程会持续运行,直到 run() 返回为止,此时该线程便死了。

上锁

大多数应用程序要求线程互相通信来同步它们的动作。在 Java 程序中最简单实现同步的方法就是上锁。为了防止同时访问共享资源,线程在使用资源的前后可以给该资源上锁和开锁。假想给复印机上锁,任一时刻只有一个职员拥有钥匙。若没有钥匙就不能使用复印机。给共享变量上锁就使得 Java 线程能够快速方便地通信和同步。某个线程若给一个对象上了锁,就可以知道没有其他线程能够访问该对象。即使在抢占式模型中,其他线程也不能够访问此对象,直到上锁的线程被唤醒、完成工作并开锁。那些试图访问一个上锁对象的线程通常会进入睡眠状态,直到上锁的线程开锁。一旦锁被打开,这些睡眠进程就会被唤醒并移到准备就绪队列中。

在 Java 编程中,所有的对象都有锁。线程可以使用 synchronized 关键字来获得锁。在任一时刻对于给定的类的实例,方法或同步的代码块只能被一个线程执行。这是因为代码在执行之前要求获得对象的锁。继续我们关于复印机的比喻,为了避免复印冲突,我们可以简单地对复印资源实行同步。如同下列的代码例子,任一时刻只允许一位职员使用复印资源。通过使用方法(在 Copier 对象中)来修改复印机状态。这个方法就是同步方法。只有一个线程能够执行一个 Copier 对象中同步代码,因此那些需要使用 Copier 对象的职员就必须排队等候。

class CopyMachine {
public synchronized void makeCopies(Document d, int nCopies) {
// only one thread executes 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.
}
}
}

时间: 2024-08-30 15:28:08

编写多线程Java应用程序常见问题的相关文章

编写的java源代码程序,用javac命令找不到

问题描述 编写的java源代码程序,用javac命令找不到 我编写的源代码程序,在命令行模式中,输入javac命令对源代码进行编译,但是生成不了字节码文件(class)? _______ 解决方案 撇开其他不说,你上述代码中,缺少一个关键字public. 应该是 public class HelloWorld{ public static void main(String[] argc){ } } 解决方案二: 嗯,另外,出现不了.class文件,那进行编译后没有什么提示吗 解决方案三: doc

使用mina框架和nio编写的java应用程序在Linux下的限制

问题描述 之前写了一个流媒体分发的应用程序,运行在Linux下经常出现打开文件过多的问题,在修改了Linux的限制后,又经常会抛出内存溢出异常,可是使用jconsole.vm.jprofiler等工具并没有发现内存泄露.在TCP连接达到一定数量(这个数量并不大,远远没有达到mina能处理的程度)的时候就会报内存溢出,不知道是什么原因?有没有遇到过类似问题的?或对Linux了解的.帮忙分析下.

编写跨平台Java程序注意事项

程序 使用Java语言编写应用程序最大的优点在于"一次编译,处处运行",然而这并不是说所有的Java程序都具有跨平台的特性,事实上,相当一部分的Java程序是不能在别的操作系统上正确运行的,那么如何才能编写一个真正的跨平台的Java程序呢?下面是在编写跨平台的Java程序是需要注意的一些事情:   1. 编写Java跨平台应用程序时,你可以选择JDK1.0,1.1,1.2或支持它们的GUI开发工具如:Jbuilder,Visual Age for Java 等等,但是必须注意你的Jav

编程-java菜鸟程序员提问:求大神给我说说线程在什么场景下用,以及多线程工作原理。谢谢

问题描述 java菜鸟程序员提问:求大神给我说说线程在什么场景下用,以及多线程工作原理.谢谢 现在java线程编程应用广泛吗?哪些时候适合或必须要用多多线程编程呢?多线程的工作原理是怎样的呢?求大神们指导指导,谢了! 解决方案 (1)线程的工作场景主要有两条: 一个是并发操作,避免阻塞和更有效利用资源.典型的例子有:在长时间工作的程序中使用工作线程避免界面失去响应.在网络下载程序中,使用多个线程提高对网络的使用效率,更快下载文件. 一个是并行,线程是处理器调度的最小单位.如果你的计算机配置了多个

Visual C#中编写多线程程序之起步

visual|程序|多线程 .NET将关于多线程的功能定义在System.Threading名字空间中.因此,要使用多线程,必须先声明引用此名字空间(using System.Threading;). 即使你没有编写多线程应用程序的经验,也可能听说过"启动线程""杀死线程"这些词,其实除了这两个外,涉及多线程方面的还有诸如"暂停线程""优先级""挂起线程""恢复线程"等等.下面将一个一个

Java与XML(二)用java编写xml的读写程序

xml|程序 Java与XML(二)用java编写xml的读写程序 这是读取xml文件的java程序,我调试好的.采用的是dom方式读取xml文件到Vector中.package src;import java.io.*;import java.util.Vector;import javax.xml.parsers.*;import org.w3c.dom.*;public class readxml { static Document document; private boolean va

在C#中编写多线程应用程序,简单!

程序|多线程 (欢迎访问www.kunwsoft.com) 以前在使用VB来实现多线程的时候,发现有一定的难度.虽然也有这样那样的方法,但都不尽人意,但在C#中,要编写多线程应用程序却相当的简单.这篇文章将作简要的介绍,以起到抛砖引玉的作用! .NET将关于多线程的功能定义在System.Threading名字空间中.因此,要使用多线程,必须先声明引用此名字空间(using System.Threading;). 即使你没有编写多线程应用程序的经验,也可能听说过"启动线程""

如何编写可通过代理访问因特网上的Web服务器的Java应用程序

本技巧将向您讲述如何编写可通过代理访问因特网上的Web服务器的Java应用程序.在Java应用程序中加入代理支持只需额外编写几行代码,且不依赖任何安全性"漏洞". 几乎所有的公司都十分关注保护自己的内部网络,以防黑客及入窃者.一种常见的安全措施是完全断开与因特网的连接.如果黑客们不能连接到您的任何一台机器,他们就不能非法进入您的系统.这种策略产生的不利副作用是,内部用户无法访问外部的因特网服务器,如Yahoo或JavaWorld.为了解决这一问题,网络管理员通常安装"代理服务

文档-编写一个java程序,将webbrowser控件嵌入进去

问题描述 编写一个java程序,将webbrowser控件嵌入进去 用java语言编写一个程序实现从网页中找到文档链接并下载和删除.拜托各位啦 解决方案 http://blog.csdn.net/b_h_l/article/details/8266899