多线程编程技术在实际编程应用中十分广泛,多线程技术的应用通过提高CPU的利用率来帮助系统提升性能,那么究竟多线程编程在什么情况下使用?怎样使用多线程呢?多线程的应用一定要适应特定的环境,线程开多了会大大增加Cpu的负担,而线程数目开少了又很难提高cpu的利用率,为此我们使用线程池来管理线程。线程池用来限制线程的数量,减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务,同时可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存使得服务器宕机。那究竟什么是多线程呢?举个形象的比喻,多线程好比人的大脑,人可以同时做好几件事情,比如我么可以一边看电视一边喝茶,而不应是非要在看完电视后才能喝茶或喝完茶后才能看电视,这就是多线程的生活中的体现。举个你更加熟悉的例子,如果你想下载三个电影,大多数人是同时选中三个电影进行下载,相信没有人会一部一部的挨个下载吧,此时我们会一边下载电影一边察看各个电影的下载进度直到所有的电影都下载完毕。当然,这三个进程下载电影的过程都会受到网络带宽的影响,这也是他们所要用到的共同资源。下面我们就来模拟同时下载三个电影的过程。
1.我们为每个电影都开启一个线程,这个线程的实现方式我选择的是集成Thread类,重写其run()方法的方式,代码如下:
package edu.review.download2;
import java.util.concurrent.ExecutorService;
public class DownloadFile extends Thread {
/*****静态变量用来模拟各线程共享资源******/
private static Object obj = new Object();
private String fileName;
private int fileNum = 0;
@Override
public void run() {
System.out.println("正在下载" + fileName);
while (fileNum < 100 ) {
fileNum++;
System.out.println("《" + fileName + "》" + "已下载:" + fileNum + "%");
tempThread();
}
if (fileNum >= 100) {
System.out.println("《" + fileName + "》" + "下载完成");
stop();
resumeByNotify();
}
}
/*****唤醒一个wait状态的进程******/
public void resumeByNotify() {
System.out.println(fileName + "动作,---通知一个");
synchronized (obj) {
obj.notify();
}
}
/******唤醒所有wait状态的进程*******/
public void resumeByNotifyAll() {
System.out.println(fileName + "动作---全通知");
synchronized (obj) {
obj.notifyAll();
}
}
public DownloadFile(String fileName) {
this.fileName = fileName;
}
/*****当下载到一半的时候阻塞进程*****/
private void tempThread(){
if(fileNum == 50){
//obj="false";
synchronized (obj) {
try {
System.out.println("《" + fileName
+ "》的下载由于网络原因被阻塞,正在等待唤醒");
obj.wait();
//obj.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
2.线程执行类TaskExecutor,代码如下:
package edu.review.download2;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class TaskExecutor {
public static void main(String[] args) {
/**** 创建一个可重用固定线程数的线程池*******/
ExecutorService pool = Executors.newCachedThreadPool();
/****** 创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口********/
DownloadFile t1 = new DownloadFile("汉武大帝");
DownloadFile t2 = new DownloadFile("秦始皇传");
DownloadFile t3 = new DownloadFile("阿甘正传");
t1.setPriority(9);
t2.setPriority(5);
t3.setPriority(1);
/********** 将线程放入池中进行执行*******/
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
/*****主线程睡眠5秒*******/
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
System.out.println("Main Thread Interrupted");
}
System.out.println("Resume By Notify");
t2.resumeByNotifyAll();
// 关闭线程池
pool.shutdown();
}
}
上面代码的实现思路是以obj类模拟共享资源,每个电影下载到一半的时候调用obj的wait()方法阻塞该进程,然后通过其中一个进程的notifyAll()操作唤醒所有的线程,让他们重新竞争cpu的使用权,直到所有的电影下载完毕。在线程执行类中我们同时下载了三部电影,然后给每个电影的下载操作开启一个线程,并将其放入到线程池中。线程池执行池对池中的所有线程进行管理,在这里我使用的是newCachedThreadPool,它创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。下面是执行结果当各个电影下载到50%的时候阻塞该线程,然后其中的一个线程执行唤醒全部操作,最后所有线程重新进入执行状态完成操作(由于数据量较大只能部分截图):
通过对比输出结果我们可以发现与我们之前分析的结果一样,这就是多线程实现多文件下载的实例,希望对于大家有所帮助。