[java多线程] - Thread&Runnable运用

时间:2023-12-28 18:57:50

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

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

[java多线程] - Thread&Runnable运用

[java多线程] - Thread&Runnable运用

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

使用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