[java多线程] - Thread&Runnable运用
负载是一个很大的话题,也是一个非常重要的话题。不管是在大的互联网软件中,还是在一般的小型软件,都对负载有一定的要求,负载过高会导致服务器压力过大;负载过低又比较浪费服务器资源,而且当高请求的时候还可能出现低效率的问题。多线程就是一种提高服务效率的方式。面对海量的用户请求,单线程肯定扛不住,那么多线程的需求也就应运而生,所以说掌握多线程的开发技术对于技术人员来说肯定是非常重要的。参考文档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运用的更多相关文章
- java 多线程--- Thread Runnable Executors
java 实现多线程的整理: Thread实现多线程的两种方式: (1)继承 Thread类,同时重载 run 方法: class PrimeThread extends Thread { long ...
- 探Java多线程Thread类和Runnable接口之间的联系
首先复习一下Java多线程实现机制,Java实现多线程方法有如下这么几种: 1.继承了(extends)Thread类 2.实现了(implements)Runnable接口 也就是说 有如下两种情 ...
- JAVA多线程Thread VS Runnable详解
要求 必备知识 本文要求基本了解JAVA编程知识. 开发环境 windows 7/EditPlus 演示地址 源文件 进程与线程 进程是程序在处理机中的一次运行.一个进程既包括其所要执行的指令,也 ...
- Java多线程Thread
转自:http://www.cnblogs.com/lwbqqyumidi/p/3804883.html Java总结篇系列:Java多线程(一) 多线程作为Java中很重要的一个知识点,在此还是 ...
- android 多线程Thread,Runnable,Handler,AsyncTask
先看两个链接: 1.http://www.2cto.com/kf/201404/290494.html 2. 链接1: android 的多线程实际上就是java的多线程.android的UI线程又称 ...
- [Java多线程]-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- [Java多线程]-Thread和Runable源码解析
多线程:(百度百科借一波定义) 多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提 ...
- 第39天学习打卡(多线程 Thread Runnable 初始并发问题 Callable )
多线程详解 01线程简介 Process与Thread 程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念. 进程则是执行程序的一次执行过程,它是一个动态的概念.是系统资源分配的 ...
- Java多线程Thread类了解和使用
创建线程的两种方式 extends Thread 类 public class WelComeApp { public static void main(String[] args) { Welcom ...
随机推荐
- The account '...' is no team with ID '...'
iOS升到9.2之后,有一个大坑,原先真机调试的开发者账号(未付费),连不了Xcode了,会弹出一个提示框提示你, The account '...' is no team with ID '...' ...
- JQuery Easy Ui dataGrid 数据表格 -->转
转至: http://www.cnblogs.com/cnjava/archive/2013/01/21/2869876.html#events 数据表格 - DataGrid 内容 概况 使用方法 ...
- 关于Inflater
在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例 ...
- bzoj3571————2016——3——12(最小乘积匹配)
bzoj3571 传送门http://www.lydsy.com/JudgeOnline/problem.php?id=3571 题解: ——————来自伟大的thy大神 http://blog.c ...
- 更改pandas dataframe 列的顺序
摘自 stackoverflow 这是我的df: Net Upper Lower Mid Zsore Answer option More than once a day 0% 0.22% -0.12 ...
- osgearth介绍(转载)-feature_labels.earth
初识osg OSG的诞生 在 1997 年时,Don Burns 由于喜欢滑翔机运动且对计算机图形学非常熟悉,在 LINUX 上写了一个控制滑翔机的小引擎,这便是 OSG 的最初雏形.后来在 1998 ...
- iOS 之 线程和进程
进程是系统调度单位,拥有自己的资源 线程是CPU调度的基本单位 进程的同步机制: 原子操作.信号量机制.自旋锁.分布式系统
- Android Studio快捷键汇总
- 去掉删除discuz x3.2 的-Powered by Discuz!
如图discuz论坛 网站标题栏的尾巴powered by discuz!是不是很想删除呢,特别是为什么会剩下短线呢?下面就叫你如何准确删除或者修改. 工具/原料 8UFTP(使用自己熟悉的网站文件上 ...
- php判断IE浏览器
<?php/** * 检测用户当前浏览器 * @return boolean 是否ie浏览器 */ function chk_ie_browser() { $userbrowser = $_SE ...