负载是一个很大的话题,也是一个非常重要的话题。不管是在大的互联网软件中,还是在一般的小型软件,都对负载有一定的要求,负载过高会导致服务器压力过大;负载过低又比较浪费服务器资源,而且当高请求的时候还可能出现低效率的问题。多线程就是一种提高服务效率的方式。面对海量的用户请求,单线程肯定扛不住,那么多线程的需求也就应运而生,所以说掌握多线程的开发技术对于技术人员来说肯定是非常重要的。参考文档http://docs.oracle.com/javase/7/docs/api/


一、Runnable使用

publicinterface Runnable {
public abstract void run();
}

  Runnable接口中,只有一个方法,就是run方法。该方法的主要作用是执行用户需要执行的代码。也就是说我们可以将我们需要在多线程环境下执行的代码放到run里面。

public class RunnableDemo {
static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("子线程:" + Thread.currentThread().getName() + ":" + sdf.format(new Date()));
try {
Thread.sleep(1000);// 休息1s
} catch (InterruptedException e) {
}
System.out.println("子线程:" + Thread.currentThread().getName() + ":" + sdf.format(new Date()));
}
}).start(); System.out.println("主线程:" + Thread.currentThread().getName() + ":" + sdf.format(new Date()));
}
} // 结果
/*
子线程:Thread-0:2015-08-27 18:25:14
主线程:main:2015-08-27 18:25:14
子线程:Thread-0:2015-08-27 18:25:15
*/

二、Thread使用

  这个类是Java中的线程基础类,基本上多线程开发不管是直接或者间接均需要依赖上该类。主要介绍几个方法:

  1、start方法: 该方法是线程执行入口,如果你需要你新建的线程开始执行,那么请调用start方法。

  2、run方法:线程执行具体代码,放用户希望执行的代码。和start的区别是,调用start方法是使用多线程方法执行,如果调用run方法,那就是单线程执行。也就是说start方法是启动线程,run方法是执行具体代码。在上面的那个例子中,如果是调用run,而不是start方法,那么一定是先打印出来两个子线程的输出值,再打印主线程的输出值。

  3、sleep方法:使当前线程休眠指定时间,参数为休眠的时间,单位毫秒。

  4、interrupt方法: 中断线程的休眠(sleep, join等操作),会产生InterruptedException异常。

public class InterruptThreadDemo {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("子线程:" + Thread.currentThread().getName() + ":" + TimeUtil.nowTime());
try {
Thread.sleep(2000); // 休息2s
} catch (InterruptedException e) {
ThrowableUtil.logThrowable(e); // 打印异常
}
System.out.println("子线程:" + Thread.currentThread().getName() + ":" + TimeUtil.nowTime());
}
});
t1.start(); // 中断线程
t1.interrupt(); System.out.println("主线程:" + Thread.currentThread().getName() + ":" + TimeUtil.nowTime());
}
}

InterruptThreadDemo

  5、isAlive&isInterrupted&isDaemon方法:检测是否处于运行状态或者是否被中断或者判断是否守护模式运行。

   6、join方法:将其他线程的执行嵌入到当前线程中,等待嵌入线程执行完毕,该线程才会被唤醒进行执行。

public class JoinThreadDemo {
public static void main(String[] args) {
final Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("子线程:" + Thread.currentThread().getName() + ":" + TimeUtil.nowTime());
try {
Thread.sleep(5000); // 休息5s
} catch (InterruptedException e) {
ThrowableUtil.logThrowable(e); // 打印异常
}
System.out.println("子线程:" + Thread.currentThread().getName() + ":" + TimeUtil.nowTime());
}
}, "1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("子线程:" + Thread.currentThread().getName() + ":" + TimeUtil.nowTime());
// 等待线程1执行完,再继续执行
try {
t1.join();
} catch (InterruptedException e) {
ThrowableUtil.logThrowable(e);
}
System.out.println("子线程:" + Thread.currentThread().getName() + ":" + TimeUtil.nowTime());
}
}, "2");
t1.start();
t2.start(); System.out.println("主线程:" + Thread.currentThread().getName() + ":" + TimeUtil.nowTime());
}
} // 结果
/*
子线程:2:2015-08-27 18:52:29 457
主线程:main:2015-08-27 18:52:29 457
子线程:1:2015-08-27 18:52:29 457
子线程:1:2015-08-27 18:52:34 458
子线程:2:2015-08-27 18:52:34 458
*/

JoinThreadDemo

  7、setDaemon方法:设置为守护模式,当主线程结束后,被设置为守护模式的线程自动结束。

  8、currentThread方法:获取当前线程。

三、多线程的实际应用

  多线程的应用是比较多的,比如说针对请求分别创建多个线程服务,下载等等。这里就弄一个下载美眉图片的小demo。

 import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream; import com.gerry.bd.util.ThrowableUtil; public class BeautyGirlPhotoDownloadDemo {
public static void main(String[] args) {
String[] categorys = new String[] { "rihan", "yule", "dongm" };
ConcurrentMap<String, BlockingQueue<String>> map = new ConcurrentHashMap<String, BlockingQueue<String>>(); // 分别启用线程来获取图片的url
for (String category : categorys) {
BlockingQueue<String> queue = new LinkedBlockingDeque<>();
map.put(category, queue); // 添加一个初始化
Thread thread = new Thread(new FetchImageUrlRunnable(category, queue), "fetchimg_" + category);
thread.start();
} File imagePath = new File("D:/image/");
// 每一个品类其两个线程去下载
for (Map.Entry<String, BlockingQueue<String>> entry : map.entrySet()) {
for (int i = 0; i < 2; i++) {
Thread thread = new Thread(new DownloadImageRunnable(imagePath, entry.getKey(), entry.getValue()), "downloadimage_" + entry.getKey() + i);
thread.start();
}
}
} /**
* 解析页面代码,保存图片url链接
*
* @author jsliuming
*
*/
public static class FetchImageUrlRunnable implements Runnable {
private String category;
private BlockingQueue<String> imageUrlQueue; public FetchImageUrlRunnable(String category, BlockingQueue<String> queue) {
this.category = category;
this.imageUrlQueue = queue;
} @Override
public void run() {
try {
String url = "";
BufferedReader br = null;
for (int i = 10; i < 100; i++) {
for (int j = 1; j < 20; j++) {
url = "http://www.mm8mm8.com/" + this.category + "/list_" + i + "_" + j + ".html";
System.out.println(Thread.currentThread().getName() + ":" + url); StringBuffer content = new StringBuffer();
try {
URLConnection connection = new URL(url).openConnection();
connection.connect();
br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
content.append(line);
}
} catch (Exception e) {
ThrowableUtil.logThrowable(e);
} finally {
if (br != null) {
try {
br.close();
} catch (Exception e) {
}
}
} // 已经拿到内容,开始解析url
if (content.length() == 0) {
// empty
break;
} else {
// 开始解析
for (String u : this.getHtmlImageUrlList(content.toString())) {
this.imageUrlQueue.put(u);
}
}
}
}
} catch (Throwable e) {
ThrowableUtil.logThrowable(e);
}
} /**
* 获取图片url
*
* @param htmlText
* @return
*/
private List<String> getHtmlImageUrlList(String htmlText) {
List<String> list = new ArrayList<String>();
Pattern pattern = Pattern.compile("<img\\s*src\\s*=\\s*\"(?<imgUrl>[^\\s\"'<>]*)\"");
Matcher matcher = pattern.matcher(htmlText);
while (matcher.find()) {
list.add(matcher.group("imgUrl"));
}
return list;
}
} /**
* 下载图片用线程
*
* @author jsliuming
*
*/
public static class DownloadImageRunnable implements Runnable {
private String category;
private BlockingQueue<String> imageUrlQueue;
private File baseFile; public DownloadImageRunnable(File path, String category, BlockingQueue<String> queue) {
this.category = category;
this.imageUrlQueue = queue;
baseFile = new File(path, this.category);
} @Override
public void run() {
int index = 0;
InputStream input = null;
ImageOutputStream ios = null;
while (true) {
try {
String imgurl = this.imageUrlQueue.take(); URLConnection connection = new URL(imgurl).openConnection();
connection.connect();
input = connection.getInputStream();
ios = new FileImageOutputStream(new File(baseFile, Thread.currentThread().getId() + "_" + index++ + ".jpg"));
byte[] buf = new byte[2048];
int n = -1;
while ((n = input.read(buf)) > 0) {
ios.write(buf, 0, n);
}
} catch (Throwable e) {
ThrowableUtil.logThrowable(e);
} finally {
if (input != null) {
try {
input.close();
} catch (Exception e) {
}
}
if (ios != null) {
try {
ios.close();
} catch (Exception e) {
}
}
}
}
} }
}

BeautyGirlPhotoDownloadDemo .java

  这个代码没有关闭的设置,所有在下载完成后,需要手动关闭。后期会改吧 。。。。。

===========================================================

使用CountDownLatch来控制下载线程下载完数据后结束程序,代码如下:

 import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream; import com.gerry.bd.util.ThrowableUtil; public class BeautyGirlPhotoDownloadDemo {
static volatile boolean fetchTheradRunning = true; // 用于控制结束线程
static final CountDownLatch latch = new CountDownLatch(3); // 用于控制结束线程 public static void main(String[] args) {
String[] categorys = new String[] { "rihan", "yule", "dongm" };
ConcurrentMap<String, BlockingQueue<String>> map = new ConcurrentHashMap<String, BlockingQueue<String>>(); // 分别启用线程来获取图片的url
for (String category : categorys) {
BlockingQueue<String> queue = new LinkedBlockingDeque<>();
map.put(category, queue); // 添加一个初始化
Thread thread = new Thread(new FetchImageUrlRunnable(category, queue), "fetchimg_" + category);
thread.start();
} File imagePath = new File("D:/image/");
// 每一个品类其两个线程去下载
for (Map.Entry<String, BlockingQueue<String>> entry : map.entrySet()) {
for (int i = 0; i < 2; i++) {
Thread thread = new Thread(new DownloadImageRunnable(imagePath, entry.getKey(), entry.getValue()), "downloadimage_" + entry.getKey() + i);
thread.start();
}
} new Thread(new Runnable() {
@Override
public void run() {
try {
latch.await();// 等待完成
fetchTheradRunning = false;
} catch (Throwable e) {
ThrowableUtil.logThrowable(e);
}
}
}).start();
} /**
* 解析页面代码,保存图片url链接
*
* @author jsliuming
*
*/
public static class FetchImageUrlRunnable implements Runnable {
private String category;
private BlockingQueue<String> imageUrlQueue; public FetchImageUrlRunnable(String category, BlockingQueue<String> queue) {
this.category = category;
this.imageUrlQueue = queue;
} @Override
public void run() {
try {
String url = "";
BufferedReader br = null;
for (int i = 10; i < 1024; i++) {
for (int j = 1; j < 21; j++) {
url = "http://www.mm8mm8.com/" + this.category + "/list_" + i + "_" + j + ".html";
System.out.println(Thread.currentThread().getName() + ":" + url); StringBuffer content = new StringBuffer();
try {
URLConnection connection = new URL(url).openConnection();
connection.connect();
br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
content.append(line);
}
} catch (Exception e) {
ThrowableUtil.logThrowable(e);
} finally {
if (br != null) {
try {
br.close();
} catch (Exception e) {
}
}
} // 已经拿到内容,开始解析url
if (content.length() == 0) {
// empty
break;
} else {
// 开始解析
for (String u : this.getHtmlImageUrlList(content.toString())) {
this.imageUrlQueue.put(u);
}
}
}
} // 完成后,通知
latch.countDown();
} catch (Throwable e) {
ThrowableUtil.logThrowable(e);
}
} /**
* 获取图片url
*
* @param htmlText
* @return
*/
private List<String> getHtmlImageUrlList(String htmlText) {
List<String> list = new ArrayList<String>();
Pattern pattern = Pattern.compile("<img\\s*src\\s*=\\s*\"(?<imgUrl>[^\\s\"'<>]*)\"");
Matcher matcher = pattern.matcher(htmlText);
while (matcher.find()) {
list.add(matcher.group("imgUrl"));
}
return list;
}
} /**
* 下载图片用线程
*
* @author jsliuming
*
*/
public static class DownloadImageRunnable implements Runnable {
private String category;
private BlockingQueue<String> imageUrlQueue;
private File baseFile; public DownloadImageRunnable(File path, String category, BlockingQueue<String> queue) {
this.category = category;
this.imageUrlQueue = queue;
baseFile = new File(path, this.category);
} @Override
public void run() {
int index = 0;
InputStream input = null;
ImageOutputStream ios = null;
while (fetchTheradRunning || this.imageUrlQueue.size() > 0) {
try {
String imgurl = null;
while (true) {
imgurl = this.imageUrlQueue.poll(10, TimeUnit.SECONDS); // 阻塞10秒
if (imgurl != null || !fetchTheradRunning) {
break;
}
}
if (imgurl == null) { // 如果url为空,那么再次循环
continue;
} URLConnection connection = new URL(imgurl).openConnection();
connection.connect();
input = connection.getInputStream();
ios = new FileImageOutputStream(new File(baseFile, Thread.currentThread().getId() + "_" + index++ + ".jpg"));
byte[] buf = new byte[2048];
int n = -1;
while ((n = input.read(buf)) > 0) {
ios.write(buf, 0, n);
}
} catch (Throwable e) {
ThrowableUtil.logThrowable(e);
} finally {
if (input != null) {
try {
input.close();
} catch (Exception e) {
}
}
if (ios != null) {
try {
ios.close();
} catch (Exception e) {
}
}
}
}
}
}
}

BeautyGirlPhotoDownloadDemo2

[java多线程] - Thread&Runnable运用的更多相关文章

  1. java 多线程--- Thread Runnable Executors

    java 实现多线程的整理: Thread实现多线程的两种方式: (1)继承 Thread类,同时重载 run 方法: class PrimeThread extends Thread { long ...

  2. 探Java多线程Thread类和Runnable接口之间的联系

    首先复习一下Java多线程实现机制,Java实现多线程方法有如下这么几种: 1.继承了(extends)Thread类 2.实现了(implements)Runnable接口 也就是说  有如下两种情 ...

  3. JAVA多线程Thread VS Runnable详解

    要求 必备知识 本文要求基本了解JAVA编程知识. 开发环境 windows 7/EditPlus 演示地址 源文件   进程与线程 进程是程序在处理机中的一次运行.一个进程既包括其所要执行的指令,也 ...

  4. Java多线程Thread

    转自:http://www.cnblogs.com/lwbqqyumidi/p/3804883.html Java总结篇系列:Java多线程(一)   多线程作为Java中很重要的一个知识点,在此还是 ...

  5. android 多线程Thread,Runnable,Handler,AsyncTask

    先看两个链接: 1.http://www.2cto.com/kf/201404/290494.html 2. 链接1: android 的多线程实际上就是java的多线程.android的UI线程又称 ...

  6. [Java多线程]-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  7. [Java多线程]-Thread和Runable源码解析

    多线程:(百度百科借一波定义) 多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提 ...

  8. 第39天学习打卡(多线程 Thread Runnable 初始并发问题 Callable )

    多线程详解 01线程简介 Process与Thread 程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念. 进程则是执行程序的一次执行过程,它是一个动态的概念.是系统资源分配的 ...

  9. Java多线程Thread类了解和使用

    创建线程的两种方式 extends Thread 类 public class WelComeApp { public static void main(String[] args) { Welcom ...

随机推荐

  1. 苹果应用商店AppStore审核中文指南 分类: ios相关 app相关 2015-07-27 15:33 84人阅读 评论(0) 收藏

    目录 1. 条款与条件 2. 功能 3. 元数据.评级与排名 4. 位置 5. 推送通知 6. 游戏中心 7. 广告 8. 商标与商业外观 9. 媒体内容 10. 用户界面 11. 购买与货币 12. ...

  2. 可用于Windows Server 2008 R2的Xbox One手柄、接收器驱动

    让客厅里的Gen8可以玩FC和PS1游戏,折腾了半天,终于将Xbox One手柄驱动弄好: http://www.drvsky.com/Microsoft/Xbox_One.htm http://ww ...

  3. UVa 10653 - Bombs! NO they are Mines!!

    题目大意:给你一个二维迷宫,给定入口和出口,找出最短路径. 无权图上的单源最短路,用BFS解决. #include <cstdio> #include <queue> #inc ...

  4. UVa 11503 - Virtual Friends

    题目大意:给出若干对朋友关系,每给出一对朋友关系,就输出二者所在关系网中的人数. 首先是对每个人编号,使用map简化编号过程,然后就是使用并查集更新集合.要注意的是当给出A和B的朋友关系时,无论A和B ...

  5. Android 使用AsyncTask 下载图片的例子,学会使用AsyncTask

    1.添加布局文件:activity_main.xml 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res ...

  6. 为什么32位操作系统最大支持4GB内存

    因为32位操作系统的地址空间为32位,地址总数为2^32,每个地址对应1Byte内存空间,这样,32位操作系统管理的最大内存空间限制为2^32Byte=4*1024*1024*1024Byte,即4G ...

  7. 推荐系统中的Graph Model

    转自:http://www.cnblogs.com/wentingtu/archive/2012/05/28/2521166.html 推荐中对graph model的研究主要有两个方面,一个是如何构 ...

  8. Carthage - 一个简单、去集中化的Cocoa依赖管理器

    作为一名新时代的90后猿 在swift大势所趋的时候  怎能不会Carthage 配置它其实很简单  下面我们一步一步来 (1)打开你的终端 输入 brew update brew install c ...

  9. NSArray和NSSet的区别

    NSSet到底什么类型? 其实它和NSArray功能性质一样,用于存储对象,属于集合: NSSet  , NSMutableSet类声明编程接口对象,无序的集合,在内存中存储方式是不连续的 像NSAr ...

  10. 用NetStream的appendBytes播放FLV

    public class MiniStream extends Sprite { private var _buffer:ByteArray = new ByteArray(); private va ...