您当前的位置:首页 > 互联网教程

使用Java多线程实现任务分发

发布时间:2025-05-24 06:50:47    发布人:远客网络

使用Java多线程实现任务分发

一、使用Java多线程实现任务分发

1、多线程下载由来已久如 FlashGet NetAnts等工具它们都是依懒于 HTTP协议的支持(Range字段指定请求内容范围)首先能读取出请求内容(即欲下载的文件)的大小划分出若干区块把区块分段分发给每个线程去下载线程从本段起始处下载数据及至段尾多个线程下载的内容最终会写入到同一个文件中

2、只研究有用的工作中的需求要把多个任务分派给Java的多个线程去执行这其中就会有一个任务列表指派到线程的策略思考已知一个待执行的任务列表指定要启动的线程数问题是每个线程实际要执行哪些任务

3、使用Java多线程实现这种任务分发的策略是任务列表连续按线程数分段先保证每线程平均能分配到的任务数余下的任务从前至后依次附加到线程中——只是数量上实际每个线程执行的任务都还是连续的如果出现那种僧多(线程)粥(任务)少的情况实际启动的线程数就等于任务数一挑一这里只实现了每个线程各扫自家门前雪动作快的完成后眼见别的线程再累都是爱莫能助

4、实现及演示代码如下由三个类实现写在了一个 Java文件中 TaskDistributor为任务分发器 Task为待执行的任务 WorkThread为自定的工作线程代码中运用了命令模式如若能配以监听器用上观察者模式来控制 UI显示就更绝妙不过了就能实现像下载中的区块着色跳跃的动感了在此定义下一步的着眼点了

5、代码中有较为详细的注释看这些注释和执行结果就很容易理解的 main()是测试方法

6、 package mon;import java util ArrayList;import java util List;/***指派任务列表给线程的分发器*@author Unmi* QQ: Email:* MSN:*/public class TaskDistributor{/***测试方法*@param args*/public static void main(String[] args){//初始化要执行的任务列表List taskList= new ArrayList();for(int i=; i<; i++){taskList add(new Task(i));}//设定要启动的工作线程数为个int threadCount=;List[] taskListPerThread= distributeTasks(taskList threadCount);System out println(实际要启动的工作线程数+taskListPerThread length);for(int i=; i< taskListPerThread length; i++){Thread workThread= new WorkThread(taskListPerThread[i] i);workThread start();}}/***把 List中的任务分配给每个线程先平均分配剩于的依次附加给前面的线程*返回的数组有多少个元素(List)就表明将启动多少个工作线程*@param taskList待分派的任务列表*@param threadCount线程数*@return列表的数组每个元素中存有该线程要执行的任务列表*/public static List[] distributeTasks(List taskList int threadCount){//每个线程至少要执行的任务数假如不为零则表示每个线程都会分配到任务int minTaskCount= taskList size()/ threadCount;//平均分配后还剩下的任务数不为零则还有任务依个附加到前面的线程中int remainTaskCount= taskList size()% threadCount;//实际要启动的线程数如果工作线程比任务还多//自然只需要启动与任务相同个数的工作线程一对一的执行//毕竟不打算实现了线程池所以用不着预先初始化好休眠的线程int actualThreadCount= minTaskCount>? threadCount: remainTaskCount;//要启动的线程数组以及每个线程要执行的任务列表List[] taskListPerThread= new List[actualThreadCount];int taskIndex=;//平均分配后多余任务每附加给一个线程后的剩余数重新声明与 remainTaskCount//相同的变量不然会在执行中改变 remainTaskCount原有值产生麻烦int remainIndces= remainTaskCount;for(int i=; i< taskListPerThread length; i++){taskListPerThread[i]= new ArrayList();//如果大于零线程要分配到基本的任务if(minTaskCount>){for(int j= taskIndex; j< minTaskCount+ taskIndex; j++){taskListPerThread[i] add(taskList get(j));}taskIndex+= minTaskCount;}//假如还有剩下的则补一个到这个线程中if(remainIndces>){taskListPerThread[i] add(taskList get(taskIndex++));remainIndces;}}//打印任务的分配情况for(int i=; i< taskListPerThread length; i++){System out println(线程+ i+的任务数+

7、 taskListPerThread[i] size()+区间[+ taskListPerThread[i] get() getTaskId()++ taskListPerThread[i] get(taskListPerThread[i] size()) getTaskId()+ ]);}return taskListPerThread;}}/***要执行的任务可在执行时改变它的某个状态或调用它的某个操作*例如任务有三个状态就绪运行完成默认为就绪态*要进一步完善可为 Task加上状态变迁的监听器因之决定UI的显示*/class Task{public static final int READY=;public static final int RUNNING=;public static final int FINISHED=;private int status;//声明一个任务的自有业务含义的变量用于标识任务private int taskId;//任务的初始化方法public Task(int taskId){this status= READY;this taskId= taskId;}/***执行任务*/public void execute(){//设置状态为运行中setStatus(Task RUNNING);System out println(当前线程 ID是+ Thread currentThread() getName()+|任务 ID是+this taskId);//附加一个延时try{Thread sleep();} catch(InterruptedException e){e printStackTrace();}//执行完成改状态为完成setStatus(FINISHED);}public void setStatus(int status){this status= status;}public int getTaskId(){return taskId;}}/***自定义的工作线程持有分派给它执行的任务列表*/class WorkThread extends Thread{//本线程待执行的任务列表你也可以指为任务索引的起始值private List taskList= null;private int threadId;/***构造工作线程为其指派任务列表及命名线程 ID*@param taskList欲执行的任务列表*@param threadId线程 ID*/public WorkThread(List taskList int threadId){this taskList= taskList;this threadId= threadId;}/***执行被指派的所有任务*/public void run(){for(Task task: taskList){task execute();}}}

8、执行结果如下注意观察每个Java多线程分配到的任务数量及区间直到所有的线程完成了所分配到的任务后程序结束

9、线程的任务数区间[ ]线程的任务数区间[ ]线程的任务数区间[ ]线程的任务数区间[ ]线程的任务数区间[ ]实际要启动的工作线程数当前线程 ID是 Thread|任务 ID是当前线程 ID是 Thread|任务 ID是当前线程 ID是 Thread|任务 ID是当前线程 ID是 Thread|任务 ID是当前线程 ID是 Thread|任务 ID是当前线程 ID是 Thread|任务 ID是当前线程 ID是 Thread|任务 ID是当前线程 ID是 Thread|任务 ID是

10、上面坦白来只算是基本功夫贴出来还真见笑了还有更为复杂的功能

二、java多线程的好处

现在世界上大多数计算机只有一块CPU.因此,充分利用CPU资源显得尤为重要。当执行单线程程序时,由于在程序发生阻塞时CPU可能会处于空闲状态。这将造成大量的计算资源的浪费。而在程序中使用多线程可以在某一个线程处于休眠或阻塞时,而CPU又恰好处于空闲状态时来运行其他的线程。这样CPU就很难有空闲的时候。因此,CPU资源就得到了充分地利用。

如果程序只完成一项任务,那只要写一个单线程的程序,并且按着执行这个任务的步骤编写代码即可。但要完成多项任务,如果还使用单线程的话,那就得在在程序中判断每项任务是否应该执行以及什么时候执行。如显示一个时钟的时、分、秒三个指针。使用单线程就得在循环中逐一判断这三个指针的转动时间和角度。如果使用三个线程分另来处理这三个指针的显示,那么对于每个线程来说就是指行一个单独的任务。这样有助于开发人员对程序的理解和维护。

当一个服务器应用程序在接收不同的客户端连接时最简单地处理方法就是为每一个客户端连接建立一个线程。然后监听线程仍然负责监听来自客户端的请求。如果这种应用程序采用单线程来处理,当监听线程接收到一个客户端请求后,开始读取客户端发来的数据,在读完数据后,read方法处于阻塞状态,也就是说,这个线程将无法再监听客户端请求了。而要想在单线程中处理多个客户端请求,就必须使用非阻塞的Socket连接和异步I/O.但使用异步I/O方式比使用同步I/O更难以控制,也更容易出错。因此,使用多线程和同步I/O可以更容易地处理类似于多请求的异步事件。

使用单线程来处理GUI事件时,必须使用循环来对随时可能发生的GUI事件进行扫描,在循环内部除了扫描GUI事件外,还得来执行其他的程序代码。如果这些代码太长,那么GUI事件就会被“冻结”,直到这些代码被执行完为止。

在现代的GUI框架(如SWING、AWT和SWT)中都使用了一个单独的事件分派线程(event dispatch thread,EDT)来对GUI事件进行扫描。当我们按下一个按钮时,按钮的单击事件函数会在这个事件分派线程中被调用。由于EDT的任务只是对GUI事件进行扫描,因此,这种方式对事件的反映是非常快的。

提高程序的执行效率一般有三种方法:

第一种方法是最容易做到的,但同时也是最昂贵的。这种方法不需要修改程序,从理论上说,任何程序都可以使用这种方法来提高执行效率。第二种方法虽然不用购买新的硬件,但这种方式不容易共享数据,如果这个程序要完成的任务需要必须要共享数据的话,这种方式就不太方便,而且启动多个线程会消耗大量的系统资源。第三种方法恰好弥补了第一种方法的缺点,而又继承了它们的优点。也就是说,既不需要购买CPU,也不会因为启太多的线程而占用大量的系统资源(在默认情况下,一个线程所占的内存空间要远比一个进程所占的内存空间小得多),并且多线程可以模拟多块CPU的运行方式,因此,使用多线程是提高程序执行效率的最廉价的方式。

三、java 多线程是什么一个处理器怎么同时处理多个程序

进程是程序在处理机中的一次运行。一个进程既包括其所要执行的指令,也包括了执行指令所需的系统资源,不同进程所占用的系统资源相对独立。所以进程是重量级的任务,它们之间的通信和转换都需要操作系统付出较大的开销。

线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己基本上不拥有系统资源,但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。所以线程是轻量级的任务,它们之间的通信和转换只需要较小的系统开销。

Java支持多线程编程,因此用Java编写的应用程序可以同时执行多个任务。Java的多线程机制使用起来非常方便,用户只需关注程序细节的实现,而不用担心后台的多任务系统。

Java语言里,线程表现为线程类。Thread线程类封装了所有需要的线程操作控制。在设计程序时,必须很清晰地区分开线程对象和运行线程,可以将线程对象看作是运行线程的控制面板。在线程对象里有很多方法来控制一个线程是否运行,睡眠,挂起或停止。线程类是控制线程行为的唯一的手段。一旦一个Java程序启动后,就已经有一个线程在运行。可通过调用Thread.currentThread方法来查看当前运行的是哪一个线程。

public static void main(String args[]){

Thread t= Thread.currentThread();

t.setName("单线程");//对线程取名为"单线程"

//设置线程优先级为8,最高为10,最低为1,默认为5

System.out.println("The running thread:"+ t);

System.out.println("Sleep time"+ i);

Thread.sleep(100);//睡眠100毫秒

}catch(InterruptedException e){//捕获异常

System.out.println("thread has wrong");

可通过继承Thread类并重写其中的run()方法来定义线程体以实现线程的具体行为,然后创建该子类的对象以创建线程。

在继承Thread类的子类ThreadSubclassName中重写run()方法来定义线程体的一般格式为:

public class ThreadSubclassName extends Thread{

.....//编写子类的构造方法,可缺省

用定义的线程子类ThreadSubclassName创建线程对象的一般格式为:

ThreadSubclassName ThreadObject=

然后,就可启动该线程对象表示的线程:

ThreadObject.start();//启动线程

应用继承类Thread的方法实现多线程的程序。本程序创建了三个单独的线程,它们分别打印自己的“Hello World!”。

class ThreadDemo extends Thread{

public ThreadDemo(String s,int d){

}catch(InterruptedException e){}

System.out.println("Hello World!"+ whoami

public static void main(String args[]){

t1= new ThreadDemo("Thread1",

t3= new ThreadDemo("Thread3",

编写多线程程序的另一种的方法是实现Runnable接口。在一个类中实现Runnable接口(以后称实现Runnable接口的类为Runnable类),并在该类中定义run()方法,然后用带有Runnable参数的Thread类构造方法创建线程。

创建线程对象可用下面的两个步骤来完成:

(1)生成Runnable类ClassName的对象

ClassName RunnableObject= new ClassName();

(2)用带有Runnable参数的Thread类构造方法创建线程对象。新创建的线程的指针将指向Runnable类的实例。用该Runnable类的实例为线程提供 run()方法---线程体。

Thread ThreadObject= new Thread(RunnableObject);

然后,就可启动线程对象ThreadObject表示的线程:

在Thread类中带有Runnable接口的构造方法有:

public Thread(Runnable target);

public Thread(Runnable target, String name);

public Thread(ThreadGroup group,Runnable target);

public Thread(ThreadGroup group,Runnable target,

其中,参数Runnable target表示该线程执行时运行target的run()方法,String name以指定名字构造线程,ThreadGroup group表示创建线程组。

class TwoThread implements Runnable{

Thread t1= Thread.currentThread();

System.out.println("正在运行的线程:"+ t1);

Thread t2= new Thread(this,"第二线程");

System.out.println("创建第二线程");

System.out.println("第一线程休眠");

}catch(InterruptedException e){

System.out.println("第一线程有错");

System.out.println("第一线程退出");

System.out.println(“第二线程的休眠时间:”

}catch(InterruptedException e){

System.out.println("线程有错");

System.out.println("第二线程退出");

public static void main(String args[]){

正在运行的线程: Thread[第一主线程,5,main

至于一个处理器同时处理多个程序,其实不是同时运行多个程序的,简单的说,如果是单核的CPU,在运行多个程序的时候其实是每个程序轮流占用CPU的,只是每个程序占用的时间很短,所以我们人为的感觉是“同时”运行多个程序。