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

    LPC1768的外部中断严格来说只有四个,分别是EINT0,EINT1,EINT2,EINT3,技术手册上有如下说明 控制这四个外部中断靠以下寄存器 这三个寄存器的0 1 2 3位分别代表中断的0 1 ...

  2. LPC2478中断控制器以及串口详解

    LPC2478的中断系统 LPC2478使用的是ARM PrimeCell向量中断控制器,一共支持32个中断向量,处于AHB空间便于系统快速访问,在中断向量的硬件优先级上还有一层可以用户自己设计的软件 ...

  3. LIBPNG

    libpng 库的源码包中有个 example.c ,里面包含PNG文件读/写的示例代码,参考示例代码和注释(虽然是英文的),可以了解大致的用法. 以下是读取PNG图片的图像数据的代码,使用前还需要按 ...

  4. 【推荐】PHP中格式化时间函数date与gmdate的区别 | 修改PHP的默认时区

    PHP中的时间有2个格式化函数:date()和gmdate(),在官方的文档中的描述为: date -- 格式化一个本地时间/日期 gmdate -- 格式化一个 GMT/UTC 日期/时间,返回的是 ...

  5. asp.net 二级域名session共享

    1.自定义类 namespace SessionShare{ public class CrossDomainCookie : IHttpModule { private string m_RootD ...

  6. JAVA-Unit01: 数据库原理 、 SQL(DDL、DML)

    Unit01: 数据库原理 . SQL(DDL.DML) SQL语句是不区分大小写的,但是行业里习惯将关键字与分关键字用大小写岔开以提高可读性. SELECT SYSDATE FROM dual DD ...

  7. 4.ICMP协议,ping和Traceroute

    1.IMCP协议介绍 前面讲到了,IP协议并不是一个可靠的协议,它不保证数据被送达,那么,自然的,保证数据送达的工作应该由其他的模块来完成.其中一个重要的模块就是ICMP(网络控制报文)协议. 当传送 ...

  8. 解callback嵌套

    function checkPassword(username,password,callback){ var pwdHash; var queryStr = 'select * from user ...

  9. 后端数据库使用 Bomb方案

    不再需要阿里云进行部署: http://docs.bmob.cn/ios/faststart/index.html?menukey=fast_start&key=start_ios

  10. AutoLayout没有相对比例布局

    怎么实现相对比例布局 比如我一个控件相对上边距的位置在整个屏幕的比例 可以用stack view来管理相对布局