Java多线程实现
java多线程编程实验总结与体会
java多线程编程实验总结与体会
[Java多线程编程实验总结与体会]
本次实验锻炼了我的Java多线程编程能力,让我更深入地了解了多线程编程的实现原理和技巧,同时也让我意识到在多线程环境下需要考虑的问题和注意事项。下面我将结合具体实验内容,分享我在实践中的体会和思考。
1. 实验环境搭建
在进行本次实验之前,我首先进行了实验环境的搭建。我选择了Java SE Development Kit 8和Eclipse作为开发工具,同时也安装了JDK8的API 文档作为参考资料。在搭建环境的过程中,我认识到Java的生态系统非常强大,附带的工具和资源也非常充足,这为我们开发和调试带来了很大的便利。
2. 多线程原理
在研究多线程编程之前,我们需要对Java语言中的线程概念有一个清晰的认识。线程是指操作系统能够进行运算调度的最小单位,是执行线程代码的路径。在Java中,线程是一种轻量级的进程,可以同时运行多个线程。每个线程都有自己的堆栈和局部变量,线程之间可以共享全局变量。
Java的多线程编程是通过Thread类和Runnable接口来实现的。
在实践中,我发现多线程编程最基本的原理是线程的并发执行。多个线程可以在同一时间内执行不同的代码,提高CPU利用率,加快程序运行速度。但是,在多线程并发执行的过程中,我们需要注意线程之间的同步问题,避免出现数据竞争和并发安全等问题。
3. 多线程的实现
在Java中,我们可以通过继承Thread类或者实现Runnable接口来创建线程。对于简单的线程,我们可以采用继承Thread类的方式来实现。例如,在实验一中,我们在Main线程内创建了两个子线程,分别用来执行奇数和偶数的累加操作。我们可以分别定义两个类OddThread和EvenThread继承Thread类,分别实现run()方法,用来执行具体的奇数和偶数累加操作。然后在Main线程内创建OddThread和EvenThread 对象,并调用start()方法来启动两个线程,并等待两个线程完成操作。
java多线程实际应用案例
java多线程实际应用案例
Java多线程是一种并发编程的方式,可以使程序同时执行多个任务,提高程序的执行效率和响应速度。下面列举了十个Java多线程实际应用案例。
1. 电商网站订单处理:在一个电商网站中,订单的处理是一个非常繁琐且耗时的工作,可以使用多线程实现订单的并发处理,提高订单处理的效率。
2. 聊天软件消息发送:在聊天软件中,用户发送消息是一个频繁的操作,可以使用多线程实现消息的并发发送,提高用户体验。
3. 数据库读写操作:在数据库的读写操作中,读操作可以使用多线程并发执行,提高数据的读取速度;写操作可以使用多线程并发执行,提高数据的写入速度。
4. 图像处理:在图像处理中,可以使用多线程实现图像的并行处理,提高图像处理的速度。
5. 视频编解码:在视频编解码中,可以使用多线程实现视频的并行编解码,提高视频的处理速度。
6. 网络爬虫:在网络爬虫中,可以使用多线程实现并发的爬取网页数据,提高爬虫的效率。
7. 游戏开发:在游戏开发中,可以使用多线程实现游戏的并行处理,提高游戏的运行速度和响应速度。
8. 大数据处理:在大数据处理中,可以使用多线程实现并发的数据处理,提高大数据处理的效率。
9. 并发服务器:在服务器开发中,可以使用多线程实现并发的请求处理,提高服务器的并发能力。
10. 并发任务调度:在任务调度中,可以使用多线程实现并发的任务执行,提高任务的执行效率。
在实际应用中,多线程不仅可以提高程序的执行效率和响应速度,还可以充分利用多核处理器的优势,实现并行计算和并发处理。然而,多线程编程也面临着诸多挑战,如线程安全、死锁、资源竞争等问题,需要设计合理的线程同步和互斥机制,确保程序的正确性和稳定性。因此,在使用多线程编程时,需要仔细考虑线程间的依赖关系和数据共享问题,合理规划线程的数量和调度策略,确保多线程程序的正确性和性能。
java多线程程序设计实验总结
java多线程程序设计实验总结
一、实验目的
本次实验旨在通过编写Java多线程程序,掌握多线程编程的基本概念和技能,理解多线程程序的运行原理,提高对Java语言的熟练度。
二、实验内容
本次实验分为三个部分:创建线程、线程同步和死锁。
2.1 创建线程
创建线程有两种方式:继承Thread类和实现Runnable接口。继承Thread类需要重写run方法,在run方法中编写线程执行的代码;实现Runnable接口需要实现run方法,并将其作为参数传入Thread
类的构造函数中。在创建多个线程时,可以使用同一个Runnable对
象或者不同的Runnable对象。
2.2 线程同步
当多个线程同时访问共享资源时,可能会出现数据不一致等问题。为
了避免这种情况,需要使用同步机制来保证各个线程之间的协调运行。常见的同步机制包括synchronized关键字和Lock接口。
synchronized关键字可以用来修饰方法或代码块,在执行该方法或代
码块时,其他所有试图访问该方法或代码块的线程都必须等待当前执
行完成后才能继续执行。
Lock接口提供了更加灵活和高级的锁机制,可以支持更多种类型的锁,如读写锁、可重入锁等。
2.3 死锁
死锁是指两个或多个线程在互相等待对方释放资源的情况下,都无法
继续执行的现象。死锁的发生通常由于程序设计不当或者资源分配不
合理所导致。
为避免死锁的发生,可以采取以下措施:避免嵌套锁、按照固定顺序
获取锁、避免长时间占用资源等。
三、实验过程
本次实验我编写了多个Java多线程程序,包括创建线程、线程同步和死锁。其中,创建线程部分我使用了继承Thread类和实现Runnable 接口两种方式来创建线程,并测试了多个线程之间的并行执行情况;
java 通用多线程工具类代码
1. 概述
在面向对象编程中,多线程技术是一项重要的技能。而 Java 作为一种流行的编程语言,也提供了丰富的多线程工具类来帮助开发者处理并发编程。本文将介绍一些 Java 中通用的多线程工具类及其代码示例,以帮助读者更好地理解和应用多线程技术。
2. 线程池(ThreadPool)
线程池是一种重要的多线程工具类,它可以有效地管理和复用线程,提高程序的性能和响应速度。以下是一个简单的线程池代码示例:
```java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void m本人n(String[] args) {
// 创建固定大小的线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
// 提交任务
for (int i = 0; i < 10; i++) {
pool.execute(new Task());
}
// 关闭线程池
pool.shutdown();
}
}
class Task implements Runnable {
public void run() {
System.out.println("Thread name: " +
Thread.currentThread().getName());
}
}
```
在上面的代码示例中,我们使用 Executors 类的newFixedThreadPool 方法创建一个固定大小的线程池,然后提交了10 个任务给线程池处理。最后调用 shutdown 方法关闭线程池。
java中多线程高并发处理案例
java中多线程高并发处理案例
一、多线程高并发处理案例
1. 购票系统:假设某电影院有100张电影票,同时有1000名观众想要购买电影票。为了保证每个观众都能成功购票,可以使用多线程高并发处理。每个观众作为一个线程,同时进行购票操作。通过使用同步锁和线程安全的数据结构,可以保证每个观众只能购买到一张电影票,避免出现票数超卖的情况。
2. 网络爬虫:假设有一个程序需要从多个网页中抓取数据,并进行处理。为了提高效率,在处理每个网页时可以使用多线程高并发处理。每个网页作为一个任务,通过创建多个线程同时进行抓取和处理操作,可以大大减少整个任务的执行时间。
3. 并行计算:假设有一个复杂的计算任务需要进行大量的计算操作。为了提高计算速度,可以使用多线程高并发处理。将任务分解成多个子任务,每个子任务作为一个线程进行计算,并最后合并结果。通过充分利用多核处理器的并行计算能力,可以大大提高计算效率。
4. 高并发请求处理:假设有一个网络服务器需要同时处理大量的请求。为了保证服务器的响应速度和吞吐量,可以使用多线程高并发处理。每个请求作为一个任务,通过创建多个线程同时处理请求,可以大大提高服务器的并发处理能力。
5. 数据库连接池:假设有一个应用程序需要频繁地进行数据库操作。为了提高数据库连接的利用率和响应速度,可以使用多线程高并发处理。通过创建多个数据库连接线程,可以复用连接对象,并同时处理多个数据库操作请求,减少连接的创建和销毁开销。
6. 文件上传下载:假设有一个文件服务器需要同时处理多个文件的上传和下载操作。为了保证服务器的响应速度和吞吐量,可以使用多线程高并发处理。每个文件操作作为一个任务,通过创建多个线程同时处理文件的上传和下载,可以大大提高服务器的并发处理能力。
JAVA多线程的使用场景与注意事项总结
JAVA多线程的使用场景与注意事项总结Java多线程是指在一个程序中同时运行多个线程,每个线程都有自
己的执行代码,但是又共享同一片内存空间和其他系统资源。多线程的使
用场景和注意事项是我们在开发中需要关注的重点,下面将详细进行总结。
一、Java多线程的使用场景:
1.提高程序的执行效率:多线程可以充分利用系统资源,将一些耗时
的操作放到一个线程中执行,避免阻塞主线程,提高程序的执行效率。
2.实现并行计算:多线程可以将任务拆分成多个子任务,每个子任务
分配给一个线程来执行,从而实现并行计算,提高计算速度。
3.响应性能提升:多线程可以提高程序的响应性能,比如在用户界面
的开发中,可以使用多线程来处理用户的输入和操作,保证界面的流畅性
和及时响应。
4.实时性要求高:多线程可以实现实时性要求高的任务,比如监控系统、实时数据处理等。
5.任务调度与资源管理:多线程可以实现任务的调度和资源的管理,
通过线程池可以更好地掌控任务的执行情况和使用系统资源。
二、Java多线程的注意事项:
1.线程安全性:多线程操作共享资源时,要注意线程安全问题。可以
通过使用锁、同步方法、同步块等方式来解决线程安全问题。
2.死锁:多线程中存在死锁问题,即多个线程相互等待对方释放资源,导致程序无法继续执行。要避免死锁问题,应尽量减少同步块的嵌套和锁
的使用。
3.内存泄漏:多线程中存在内存泄漏问题,即线程结束后,线程的资
源没有得到释放,导致内存占用过高。要避免内存泄漏问题,应及时释放
线程资源。
4.上下文切换:多线程的切换会带来上下文切换的开销,影响程序的
如何在Java中使用多线程进行并发编程
如何在Java中使用多线程进行并发编程
Java作为一种面向对象的编程语言,可以支持多线程并发编程。使用Java多线程可以使程序能够有效地利用多核处理器,提高程
序的计算速度和并发性能。在本文中,我们将探讨如何在Java中
使用多线程进行并发编程。
一、什么是多线程
多线程是指在单个程序中同时运行多个线程,每个线程都可以
独立地执行不同的任务。与单线程相比,多线程可以提高程序的
并发性能,使程序更加高效地执行各种任务。
Java中使用多线程编程,可以使用线程对象实现并发性能。线
程对象是Java平台提供的一种机制,可以使多个线程在同一个应
用程序中运行。线程对象可以直接通过Java API访问,从而为开
发人员提供了创建和控制线程的方法。
二、创建线程
Java中实现多线程最常用的方法是创建Thread类的对象,并重
写run()方法。线程执行的代码通常写在run()方法中。创建线程的
方式有两种:一种是继承Thread类,另一种是实现Runnable接口。
继承Thread类创建线程
继承Thread类,必须实现run()方法。run()方法是线程的一个
主要方法,是用来描述线程如何运行的。
```
public class MyThread extends Thread {
public void run() {
// 线程执行的代码
}
}
```
实现Runnable接口创建线程
实现Runnable接口,必须实现run()方法。Thread类实现了Runnable接口,构造函数中可以传递一个Runnable类型的参数,这样可以使一个Thread对象关联一个Runnable对象,从而启动一个新的线程。
java 多线程理解
java 多线程理解
Java多线程是指在同一时间内,程序中有多个线程在同时执行。这种并发性质让程序可以更有效地利用CPU资源,提高程序的响应速度和并发处理能力。
Java多线程的实现方式有两种,一种是继承Thread类,另一种是实现Runnable接口。对于简单的多线程任务,继承Thread类更为简单,而对于复杂的任务,实现Runnable接口更为灵活。
Java多线程的核心概念包括线程安全、同步和互斥。线程安全
是指多个线程同时调用一个对象或方法时,不会发生错误或数据损坏。同步是指多个线程在执行时,需要互相协调和配合,确保数据的正确性和一致性。互斥是指多个线程在访问共享资源时,需要通过加锁和释放锁来保证同一时间只有一个线程可以访问。
Java多线程的应用领域非常广泛,例如服务器端的并发处理、
多媒体处理、网络编程等等。理解Java多线程的核心概念和实现方式,对于开发高并发、高可用的程序非常重要。
- 1 -
多线程的四种实现方式
多线程的四种实现⽅式
JDK5.0之后Java多线程的实现⽅式变成了四种,下⾯来简单的列举⼀下,如果需要更深⼊的了解,强烈建议阅读⼀下源码。
⼀、继承Thread类重写run()⽅法:
1. 创建⼀个继承于Thread类的⼦类
2. 重写Thread类的run() --> 将此线程执⾏的操作声明在run()中
3. 创建Thread类的⼦类的对象
4. 通过此对象调⽤start()
1 // 1、创建⼀个继承于Thread类的⼦类
2 class Test1 extends Thread {
3
4 // 2、重写Thread类的run()
5 @Override
6 public void run() {
7 //Thread.currentThread().getName():获取当前线程的名字
8 System.out.println("线程需要执⾏的代码" + "->"
9 + Thread.currentThread().getName());
10 }
11
12 }
13
14 public class ThreadTest1 {
15 public static void main(String[] args) {
16 // 3、创建Thread类的⼦类的对象
17 Test1 test1 = new Test1();
18
19 //多线程当然可以创建多个对象来开启多个线程
20 Test1 test2 = new Test1();
21
22 // 4、通过此对象调⽤start()⽅法启动线程
23 //start()⽅法的作⽤:1)启动当前线程 2)调⽤当前线程的run()⽅法
创建多线程的三种方法
创建多线程的三种方法
创建多线程是多任务处理的一种方式,可以同时执行多个任务,提高程序的执行效率。在Java中,创建多线程有三种方法:继承Thread类、实现Runnable接口和使用线程池。
第一种方法是通过继承Thread类来创建多线程。首先,创建一个继承自Thread的子类,并重写其run方法。在run方法中定义线程要执行的任务。然后,创建子类的实例,并调用start方法启动线程。通过start方法,JVM会自动调用run方法,并在一个新的线程中执行。这种方法的优点是简单直观,适用于简单的多线程任务。但是,由于Java是单继承的,如果已经继承了其他类,则无法使用这种方法创建多线程。
第二种方法是实现Runnable接口来创建多线程。与第一种方法不同的是,实现Runnable接口可以避免单继承的限制。首先,创建一个实现了Runnable接口的类,并实现其run方法。然后,创建该类的实例,并将其作为参数传递给Thread类的构造方法。最后,调用Thread类的start方法启动线程。通过实现Runnable接口,一个类可以同时被多个线程共享,提高了代码的复用性。此外,实现Runnable接口还可以实现资源的共享和线程的通信。
第三种方法是使用线程池来创建多线程。线程池是一种管理和复用线程的机制,可以提高线程的效率和资源的利用率。使用线程池可
以避免频繁创建和销毁线程的开销。Java提供了Executors类来创建线程池。首先,通过Executors类的静态方法创建一个线程池,例如newFixedThreadPool方法创建一个固定大小的线程池。然后,通过submit方法将任务提交给线程池执行。线程池会自动分配线程来执行任务,并复用空闲线程。最后,通过调用shutdown方法关闭线程池。使用线程池可以更好地控制线程的数量,避免线程过多导致系统资源的浪费。
JAVA开发中的多线程编程技术
JAVA开发中的多线程编程技术Java作为一种广泛应用于企业级应用以及各种工业自动化系统
的编程语言,其对于处理多线程并发的问题起到了巨大的作用。
在Java开发过程中,我们经常会遇到需要多线程并发处理的情况,比如高并发的Web服务、大数据处理、图像处理等等。如何正确
合理的使用Java多线程技术是一个非常重要的问题。本文将详细
讲解Java开发中的多线程编程技术。
1.了解Java线程模型
Java语言具有完善的线程模型,并提供了Thread类以及Runnable接口,方便程序员进行多线程编程。在进行Java多线程
编程的过程中,必须先理解Java的线程模型,包括线程的创建、
使用、同步、互斥、线程间通信等。同时,也要掌握Java虚拟机
的内存结构以及线程调度器的工作原理,这些对多线程编程至关
重要。
2.使用synchronized实现线程同步
在多线程编程中,需要涉及到许多复杂的操作,如多个线程同时对同一共享数据进行读写操作会造成数据不一致等问题。这时需要使用synchronized关键字来进行同步。通过对象锁的机制,保证每个时间段只有一个线程能够访问同一个对象的同步代码块。当线程进入一个对象的同步块时,将获得该对象的锁,只有等线程退出同步块或发生异常时才会释放锁,其他线程才能进入同步块。通过synchronized关键字的同步机制能控制线程的读写顺序,使多个线程协同工作,防止数据不一致的问题。
3.使用volatile变量实现线程间通信
在多线程编程中,需要进行线程间的通信。在Java语言中,volatile变量可以用来实现线程间的通信。当一个变量被声明为volatile变量后,所有线程对这个变量的读写操作都会直接在内存中进行,而不会使用线程的缓存中间值。这样可以避免数据缓存的不一致,并保证在不同线程中读写的顺序是一致的,从而实现了线程之间的通信。
java中实现多线程的方法
java中实现多线程的方法
Java是一种非常强大的编程语言,它支持多线程,这是Java的一个重要特性。多线程允许同时执行多个任务,从而大大提高了应用程序的效率和性能。
在Java中实现多线程的方法有很多种,下面我们将一步步地阐述这些方法。
第一种方法是继承Thread类。我们可以在Java中创建一个继承Thread类的子类,并在子类中实现run()方法。在run()方法中编写多线程代码。以下是示例代码:
```
class MyThread extends Thread {
public void run() {
//多线程代码
}
}
```
在上述代码中,我们创建了一个名为MyThread的子类,并重写了Thread类的run()方法。
第二种方法是实现Runnable接口。这种方法需要创建一个实现Runnable接口的类,然后实例化一个Thread对象并将实现Runnable 接口的类作为参数传递给Thread对象。以下是示例代码:
class MyRunnable implements Runnable {
public void run() {
//多线程代码
}
}
public class Main {
public static void main(String[] args) {
MyRunnable obj = new MyRunnable();
Thread thread = new Thread(obj);
thread.start();
}
}
```
在上述代码中,我们创建了一个名为MyRunnable的类,并实现了Runnable接口。我们在主类中创建了一个MyRunnable对象,并通过传递该对象作为参数创建了一个Thread对象。最后启动线程。
java多线程经典实例
java多线程经典实例
以下是一些经典的Java多线程实例:
1. 生产者消费者问题:使用线程实现一个简单的生产者消费者模型,其中生产者将物品放入缓冲区,消费者从缓冲区中取出物品。
java
class Producer implements Runnable {
private Buffer buffer;
public Producer(Buffer buffer) {
this.buffer = buffer;
}
public void run() {
for (int i = 0; i < 10; i++) {
buffer.produce();
}
}
}
class Consumer implements Runnable {
private Buffer buffer;
public Consumer(Buffer buffer) { this.buffer = buffer;
}
public void run() {
for (int i = 0; i < 10; i++) {
buffer.consume();
}
}
}
class Buffer {
private List<Integer> items;
private int capacity;
public Buffer(int capacity) {
this.capacity = capacity;
items = new ArrayList<>();
}
public synchronized void produce() {
创建多线程的几种方法
创建多线程的几种方法
创建多线程是现代编程中常用的一种技术,它可以使程序同时执行多个任务,提高程序的效率和响应速度。本文将介绍几种常见的创建多线程的方法。
1. 继承Thread类
Java中,创建多线程最常见的方法是继承Thread类。我们可以定义一个类,继承Thread类,并重写run方法,在run方法中编写线程要执行的代码。然后,创建该类的实例并调用start方法,即可启动线程。
2. 实现Runnable接口
除了继承Thread类,Java还提供了另一种创建多线程的方法,即实现Runnable接口。我们可以定义一个类,实现Runnable接口,并实现其中的run方法。然后,创建该类的实例,并将其作为参数传递给Thread类的构造方法,最后调用start方法启动线程。
3. 使用Callable和Future
Java中,除了上述两种方式,还可以使用Callable和Future接口来创建多线程。Callable接口类似于Runnable接口,但它可以返回线程执行的结果。我们可以定义一个类,实现Callable接口,并实现其中的call方法,在call方法中编写线程要执行的代码,并返
回结果。然后,创建该类的实例,并将其作为参数传递给FutureT ask类的构造方法,最后调用start方法启动线程。
4. 使用线程池
在实际开发中,创建线程时如果频繁地创建和销毁线程,会造成系统资源的浪费。为了解决这个问题,可以使用线程池来管理线程。线程池可以重复利用已创建的线程,避免频繁地创建和销毁线程,从而提高程序的性能。
Java多线程编程技巧详解
Java多线程编程技巧详解
Java是一种广泛使用的编程语言,而多线程编程则是Java中一个重要的开发领域。在多线程编程中,开发者需要了解并掌握一定的技巧,以避免线程之间的冲突和死锁等问题。本文将详细介绍Java多线程编程的常用技巧,帮助开发者轻松掌握多线程编程的精髓。
一、线程的创建与启动
1. 继承Thread类创建线程:直接继承Thread类,并覆盖run()方法实现线程主体。
```
public class MyThread extends Thread{
public void run(){
//线程执行体
}
}
MyThread myThread = new MyThread();
myThread.start();
```
2. 实现Runnable接口创建线程:实现Runnable接口,并在类中实例化一个Thread对象。
```
public class MyRunnable implements Runnable{
public void run(){
//线程执行体
}
}
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
```
二、线程的处理与管理
1. 同步方法:synchronized关键字用于保护共享数据不被多个线程同时访问。
```
public class SynchronizedDemo implements Runnable {
private int count;
java多线程常用方法
java多线程常用方法
Java多线程是Java语言的一项重要特性,它允许程序同时执行多个任务,提高了程序的效率和性能。在多线程编程中,有一些常用的方法和技巧可以帮助我们更好地控制和管理线程。本文将介绍一些常用的Java多线程方法。
1. 线程的创建与启动:Java中创建线程有两种方式,一种是继承Thread类,另一种是实现Runnable接口。继承Thread类需要重写run()方法,实现Runnable接口需要实现run()方法,并将Runnable对象作为参数传递给Thread对象。然后通过调用start()方法启动线程。
2. 线程的休眠:使用Thread的sleep()方法可以使线程暂停一段时间,单位是毫秒。这个方法常用于模拟耗时操作,或者在某些情况下需要让线程暂停一段时间。
3. 线程的优先级:每个线程都有一个优先级,用于决定线程在竞争CPU资源时的顺序。通过Thread类的setPriority()方法可以设置线程的优先级,取值范围是1到10,默认是5。优先级高的线程有更大的概率先被执行,但并不能保证绝对的执行顺序。
4. 线程的加入:使用Thread的join()方法可以让一个线程等待另一个线程执行完毕。在调用join()方法时,当前线程会暂停执行,直到被调用的线程执行完毕才会继续执行。
5. 线程的中断:使用Thread的interrupt()方法可以中断一个线程。当调用interrupt()方法时,被中断的线程会收到一个中断信号,可以根据需要做出相应的处理。
6. 线程的同步:在多线程编程中,经常会遇到多个线程同时访问共享资源的情况。为了保证数据的一致性和避免竞态条件,可以使用synchronized关键字来实现线程的同步。synchronized关键字可以修饰方法或代码块,用于保证同一时间只有一个线程执行被修饰的代码。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
下面要和大家分享的是Java多线程的实践,其实Java增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活。本文通过一个网络服务器模型,来实践Java5的多线程编程,该模型中使用了Java5中的线程池,阻塞队列,可重入锁等,还实践了Callable,Future 等接口,并使用了Java 的另外一个新特性泛型。
简介
本文将实现一个网络服务器模型,一旦有客户端连接到该服务器,则启动一个新线程为该连接服务,服务内容为往客户端输送一些字符信息。一个典型的网络服务器模型如下:
1. 建立监听端口。
2. 发现有新连接,接受连接,启动线程,执行服务线程。
3. 服务完毕,关闭线程。
这个模型在大部分情况下运行良好,但是需要频繁的处理用户请求而每次请求需要的服务又是简短的时候,系统会将大量的时间花费在线程的创建销毁。Java 5的线程池克服了这些缺点。通过对重用线程来执行多个任务,避免了频繁线程的创建与销毁开销,使得服务器的性能方面得到很大提高。因此,本文的网络服务器模型将如下:
1. 建立监听端口,创建线程池。
2. 发现有新连接,使用线程池来执行服务任务。
3. 服务完毕,释放线程到线程池。
下面详细介绍如何使用Java 5的concurrent包提供的API来实现该服务器。
初始化
初始化包括创建线程池以及初始化监听端口。创建线程池可以通过调用java.util.concurrent.Executors类里的静态方法newChahedThreadPool或是newFixedThreadPool来创建,也可以通过新建一个
java.util.concurrent.ThreadPoolExecutor实例来执行任务。这里我们采用newFixedThreadPool方法来建立线程池。
ExecutorService pool = Executors.newFixedThreadPool(10);
表示新建了一个线程池,线程池里面有10个线程为任务队列服务。
使用ServerSocket对象来初始化监听端口。
Java代码
private static final int PORT = 19527;
serverListenSocket = new ServerSocket(PORT);
serverListenSocket.setReuseAddress(true);
服务新连接
当有新连接建立时,accept返回时,将服务任务提交给线程池执行。
Java代码
while(true){
Socket socket = serverListenSocket.accept();
pool.execute(new ServiceThread(socket));
}
这里使用线程池对象来执行线程,减少了每次线程创建和销毁的开销。任务执行完毕,线程释放到线程池。
服务任务
服务线程ServiceThread维护一个count来记录服务线程被调用的次数。每当服务任务被调用一次时,count 的值自增1,因此ServiceThread提供一个increaseCount和getCount的方法,分别将count值自增1和取得该count值。由于可能多个线程存在竞争,同时访问count,因此需要加锁机制,在Java 5之前,我们只能使用synchronized来锁定。Java 5中引入了性能更加粒度更细的重入锁ReentrantLock。我们使用ReentrantLock保证代码线程安全。下面是具体代码:
Java代码
private static ReentrantLock lock = new ReentrantLock ();
private static int count = 0;
private int getCount(){
int ret = 0;
try{
lock.lock();
ret = count;
}finally{
lock.unlock();
}
return ret;
}
private void increaseCount(){
try{
lock.lock();
++count;
}finally{
lock.unlock();
}
}
服务线程在开始给客户端打印一个欢迎信息,
Java代码
increaseCount();
int curCount = getCount();
helloString = "hello, id = " + curCount+"\r\n";
dos = new DataOutputStream(connectedSocket.getOutputStream()); dos.write(helloString.getBytes());
然后使用ExecutorService的submit方法提交一个Callable的任务,返回一个Future接口的引用。这种做法对费时的任务非常有效,submit任务之后可以继续执行下面的代码,然后在适当的位置可以使用Future的get方法来获取结果,如果这时候该方法已经执行完毕,则无需等待即可获得结果,如果还在执行,则等待到运行完毕。
Java代码
ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(new TimeConsumingTask());
dos.write("let's do soemthing other".getBytes());
String result = future.get();
dos.write(result.getBytes());
其中TimeConsumingTask实现了Callable接口
class TimeConsumingTask implements Callable {
public String call() throws Exception {
System.out.println
("It's a time-consuming task,
you'd better retrieve your result in the furture");
return "ok, here's the result: It takes me lots of time to produce this result";
}
}
这里使用了Java 5的另外一个新特性泛型,声明TimeConsumingTask的时候使用了String做为类型参数。必须实现Callable接口的call函数,其作用类似与Runnable中的run函数,在call函数里写入要执行的代码,其返回值类型等同于在类声明中传入的类型值。在这段程序中,我们提交了一个Callable的任务,然后程序不会堵塞,而是继续执行dos.write("let's do soemthing other".getBytes());当程序执行到String result = future.get()时如果call函数已经执行完毕,则取得返回值,如果还在执行,则等待其执行完毕。
服务器端的完整实现
服务器端的完整实现代码如下: