[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。

  1 import java.io.BufferedReader;
  2 import java.io.File;
  3 import java.io.InputStream;
  4 import java.io.InputStreamReader;
  5 import java.net.URL;
  6 import java.net.URLConnection;
  7 import java.util.ArrayList;
  8 import java.util.List;
  9 import java.util.Map;
 10 import java.util.concurrent.BlockingQueue;
 11 import java.util.concurrent.ConcurrentHashMap;
 12 import java.util.concurrent.ConcurrentMap;
 13 import java.util.concurrent.LinkedBlockingDeque;
 14 import java.util.regex.Matcher;
 15 import java.util.regex.Pattern;
 16
 17 import javax.imageio.stream.FileImageOutputStream;
 18 import javax.imageio.stream.ImageOutputStream;
 19
 20 import com.gerry.bd.util.ThrowableUtil;
 21
 22 public class BeautyGirlPhotoDownloadDemo {
 23     public static void main(String[] args) {
 24         String[] categorys = new String[] { "rihan", "yule", "dongm" };
 25         ConcurrentMap<String, BlockingQueue<String>> map = new ConcurrentHashMap<String, BlockingQueue<String>>();
 26
 27         // 分别启用线程来获取图片的url
 28         for (String category : categorys) {
 29             BlockingQueue<String> queue = new LinkedBlockingDeque<>();
 30             map.put(category, queue); // 添加一个初始化
 31             Thread thread = new Thread(new FetchImageUrlRunnable(category, queue), "fetchimg_" + category);
 32             thread.start();
 33         }
 34
 35         File imagePath = new File("D:/image/");
 36         // 每一个品类其两个线程去下载
 37         for (Map.Entry<String, BlockingQueue<String>> entry : map.entrySet()) {
 38             for (int i = 0; i < 2; i++) {
 39                 Thread thread = new Thread(new DownloadImageRunnable(imagePath, entry.getKey(), entry.getValue()), "downloadimage_" + entry.getKey() + i);
 40                 thread.start();
 41             }
 42         }
 43     }
 44
 45     /**
 46      * 解析页面代码,保存图片url链接
 47      *
 48      * @author jsliuming
 49      *
 50      */
 51     public static class FetchImageUrlRunnable implements Runnable {
 52         private String category;
 53         private BlockingQueue<String> imageUrlQueue;
 54
 55         public FetchImageUrlRunnable(String category, BlockingQueue<String> queue) {
 56             this.category = category;
 57             this.imageUrlQueue = queue;
 58         }
 59
 60         @Override
 61         public void run() {
 62             try {
 63                 String url = "";
 64                 BufferedReader br = null;
 65                 for (int i = 10; i < 100; i++) {
 66                     for (int j = 1; j < 20; j++) {
 67                         url = "http://www.mm8mm8.com/" + this.category + "/list_" + i + "_" + j + ".html";
 68                         System.out.println(Thread.currentThread().getName() + ":" + url);
 69
 70                         StringBuffer content = new StringBuffer();
 71                         try {
 72                             URLConnection connection = new URL(url).openConnection();
 73                             connection.connect();
 74                             br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
 75                             String line = null;
 76                             while ((line = br.readLine()) != null) {
 77                                 content.append(line);
 78                             }
 79                         } catch (Exception e) {
 80                             ThrowableUtil.logThrowable(e);
 81                         } finally {
 82                             if (br != null) {
 83                                 try {
 84                                     br.close();
 85                                 } catch (Exception e) {
 86                                 }
 87                             }
 88                         }
 89
 90                         // 已经拿到内容,开始解析url
 91                         if (content.length() == 0) {
 92                             // empty
 93                             break;
 94                         } else {
 95                             // 开始解析
 96                             for (String u : this.getHtmlImageUrlList(content.toString())) {
 97                                 this.imageUrlQueue.put(u);
 98                             }
 99                         }
100                     }
101                 }
102             } catch (Throwable e) {
103                 ThrowableUtil.logThrowable(e);
104             }
105         }
106
107         /**
108          * 获取图片url
109          *
110          * @param htmlText
111          * @return
112          */
113         private List<String> getHtmlImageUrlList(String htmlText) {
114             List<String> list = new ArrayList<String>();
115             Pattern pattern = Pattern.compile("<img\\s*src\\s*=\\s*\"(?<imgUrl>[^\\s\"‘<>]*)\"");
116             Matcher matcher = pattern.matcher(htmlText);
117             while (matcher.find()) {
118                 list.add(matcher.group("imgUrl"));
119             }
120             return list;
121         }
122     }
123
124     /**
125      * 下载图片用线程
126      *
127      * @author jsliuming
128      *
129      */
130     public static class DownloadImageRunnable implements Runnable {
131         private String category;
132         private BlockingQueue<String> imageUrlQueue;
133         private File baseFile;
134
135         public DownloadImageRunnable(File path, String category, BlockingQueue<String> queue) {
136             this.category = category;
137             this.imageUrlQueue = queue;
138             baseFile = new File(path, this.category);
139         }
140
141         @Override
142         public void run() {
143             int index = 0;
144             InputStream input = null;
145             ImageOutputStream ios = null;
146             while (true) {
147                 try {
148                     String imgurl = this.imageUrlQueue.take();
149
150                     URLConnection connection = new URL(imgurl).openConnection();
151                     connection.connect();
152                     input = connection.getInputStream();
153                     ios = new FileImageOutputStream(new File(baseFile, Thread.currentThread().getId() + "_" + index++ + ".jpg"));
154                     byte[] buf = new byte[2048];
155                     int n = -1;
156                     while ((n = input.read(buf)) > 0) {
157                         ios.write(buf, 0, n);
158                     }
159                 } catch (Throwable e) {
160                     ThrowableUtil.logThrowable(e);
161                 } finally {
162                     if (input != null) {
163                         try {
164                             input.close();
165                         } catch (Exception e) {
166                         }
167                     }
168                     if (ios != null) {
169                         try {
170                             ios.close();
171                         } catch (Exception e) {
172                         }
173                     }
174                 }
175             }
176         }
177
178     }
179 }

BeautyGirlPhotoDownloadDemo .java

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

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

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

  1 import java.io.BufferedReader;
  2 import java.io.File;
  3 import java.io.InputStream;
  4 import java.io.InputStreamReader;
  5 import java.net.URL;
  6 import java.net.URLConnection;
  7 import java.util.ArrayList;
  8 import java.util.List;
  9 import java.util.Map;
 10 import java.util.concurrent.BlockingQueue;
 11 import java.util.concurrent.ConcurrentHashMap;
 12 import java.util.concurrent.ConcurrentMap;
 13 import java.util.concurrent.CountDownLatch;
 14 import java.util.concurrent.LinkedBlockingDeque;
 15 import java.util.concurrent.TimeUnit;
 16 import java.util.regex.Matcher;
 17 import java.util.regex.Pattern;
 18
 19 import javax.imageio.stream.FileImageOutputStream;
 20 import javax.imageio.stream.ImageOutputStream;
 21
 22 import com.gerry.bd.util.ThrowableUtil;
 23
 24 public class BeautyGirlPhotoDownloadDemo {
 25     static volatile boolean fetchTheradRunning = true; // 用于控制结束线程
 26     static final CountDownLatch latch = new CountDownLatch(3); // 用于控制结束线程
 27
 28     public static void main(String[] args) {
 29         String[] categorys = new String[] { "rihan", "yule", "dongm" };
 30         ConcurrentMap<String, BlockingQueue<String>> map = new ConcurrentHashMap<String, BlockingQueue<String>>();
 31
 32         // 分别启用线程来获取图片的url
 33         for (String category : categorys) {
 34             BlockingQueue<String> queue = new LinkedBlockingDeque<>();
 35             map.put(category, queue); // 添加一个初始化
 36             Thread thread = new Thread(new FetchImageUrlRunnable(category, queue), "fetchimg_" + category);
 37             thread.start();
 38         }
 39
 40         File imagePath = new File("D:/image/");
 41         // 每一个品类其两个线程去下载
 42         for (Map.Entry<String, BlockingQueue<String>> entry : map.entrySet()) {
 43             for (int i = 0; i < 2; i++) {
 44                 Thread thread = new Thread(new DownloadImageRunnable(imagePath, entry.getKey(), entry.getValue()), "downloadimage_" + entry.getKey() + i);
 45                 thread.start();
 46             }
 47         }
 48
 49         new Thread(new Runnable() {
 50             @Override
 51             public void run() {
 52                 try {
 53                     latch.await();// 等待完成
 54                     fetchTheradRunning = false;
 55                 } catch (Throwable e) {
 56                     ThrowableUtil.logThrowable(e);
 57                 }
 58             }
 59         }).start();
 60     }
 61
 62     /**
 63      * 解析页面代码,保存图片url链接
 64      *
 65      * @author jsliuming
 66      *
 67      */
 68     public static class FetchImageUrlRunnable implements Runnable {
 69         private String category;
 70         private BlockingQueue<String> imageUrlQueue;
 71
 72         public FetchImageUrlRunnable(String category, BlockingQueue<String> queue) {
 73             this.category = category;
 74             this.imageUrlQueue = queue;
 75         }
 76
 77         @Override
 78         public void run() {
 79             try {
 80                 String url = "";
 81                 BufferedReader br = null;
 82                 for (int i = 10; i < 1024; i++) {
 83                     for (int j = 1; j < 21; j++) {
 84                         url = "http://www.mm8mm8.com/" + this.category + "/list_" + i + "_" + j + ".html";
 85                         System.out.println(Thread.currentThread().getName() + ":" + url);
 86
 87                         StringBuffer content = new StringBuffer();
 88                         try {
 89                             URLConnection connection = new URL(url).openConnection();
 90                             connection.connect();
 91                             br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
 92                             String line = null;
 93                             while ((line = br.readLine()) != null) {
 94                                 content.append(line);
 95                             }
 96                         } catch (Exception e) {
 97                             ThrowableUtil.logThrowable(e);
 98                         } finally {
 99                             if (br != null) {
100                                 try {
101                                     br.close();
102                                 } catch (Exception e) {
103                                 }
104                             }
105                         }
106
107                         // 已经拿到内容,开始解析url
108                         if (content.length() == 0) {
109                             // empty
110                             break;
111                         } else {
112                             // 开始解析
113                             for (String u : this.getHtmlImageUrlList(content.toString())) {
114                                 this.imageUrlQueue.put(u);
115                             }
116                         }
117                     }
118                 }
119
120                 // 完成后,通知
121                 latch.countDown();
122             } catch (Throwable e) {
123                 ThrowableUtil.logThrowable(e);
124             }
125         }
126
127         /**
128          * 获取图片url
129          *
130          * @param htmlText
131          * @return
132          */
133         private List<String> getHtmlImageUrlList(String htmlText) {
134             List<String> list = new ArrayList<String>();
135             Pattern pattern = Pattern.compile("<img\\s*src\\s*=\\s*\"(?<imgUrl>[^\\s\"‘<>]*)\"");
136             Matcher matcher = pattern.matcher(htmlText);
137             while (matcher.find()) {
138                 list.add(matcher.group("imgUrl"));
139             }
140             return list;
141         }
142     }
143
144     /**
145      * 下载图片用线程
146      *
147      * @author jsliuming
148      *
149      */
150     public static class DownloadImageRunnable implements Runnable {
151         private String category;
152         private BlockingQueue<String> imageUrlQueue;
153         private File baseFile;
154
155         public DownloadImageRunnable(File path, String category, BlockingQueue<String> queue) {
156             this.category = category;
157             this.imageUrlQueue = queue;
158             baseFile = new File(path, this.category);
159         }
160
161         @Override
162         public void run() {
163             int index = 0;
164             InputStream input = null;
165             ImageOutputStream ios = null;
166             while (fetchTheradRunning || this.imageUrlQueue.size() > 0) {
167                 try {
168                     String imgurl = null;
169                     while (true) {
170                         imgurl = this.imageUrlQueue.poll(10, TimeUnit.SECONDS); // 阻塞10秒
171                         if (imgurl != null || !fetchTheradRunning) {
172                             break;
173                         }
174                     }
175                     if (imgurl == null) { // 如果url为空,那么再次循环
176                         continue;
177                     }
178
179                     URLConnection connection = new URL(imgurl).openConnection();
180                     connection.connect();
181                     input = connection.getInputStream();
182                     ios = new FileImageOutputStream(new File(baseFile, Thread.currentThread().getId() + "_" + index++ + ".jpg"));
183                     byte[] buf = new byte[2048];
184                     int n = -1;
185                     while ((n = input.read(buf)) > 0) {
186                         ios.write(buf, 0, n);
187                     }
188                 } catch (Throwable e) {
189                     ThrowableUtil.logThrowable(e);
190                 } finally {
191                     if (input != null) {
192                         try {
193                             input.close();
194                         } catch (Exception e) {
195                         }
196                     }
197                     if (ios != null) {
198                         try {
199                             ios.close();
200                         } catch (Exception e) {
201                         }
202                     }
203                 }
204             }
205         }
206     }
207 }

BeautyGirlPhotoDownloadDemo2

时间: 2024-10-14 12:51:32

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

java 多线程--- Thread Runnable Executors

java 实现多线程的整理: Thread实现多线程的两种方式: (1)继承 Thread类,同时重载 run 方法: class PrimeThread extends Thread { long minPrime; primeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime } } PrimeThread p = new

java多线程(thread/runnable)

1 class Thread1 extends Thread Thread1 mTh1=new Thread1("A"); Thread1 mTh2=new Thread1("B"); mTh1.start(); mTh2.start(); 2 class Thread2 implements Runnable new Thread(new Thread2("C")).start(); new Thread(new Thread2("D

Java多线程-Thread&amp;Runnable的关系

Thread创建多线程: MyThread.class package com.test.interview; public class MyThread extends Thread { private String name; public MyThread(String name) { this.name = name; } @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("

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

首先复习一下Java多线程实现机制,Java实现多线程方法有如下这么几种: 1.继承了(extends)Thread类 2.实现了(implements)Runnable接口 也就是说  有如下两种情况 情况1: 继承Thread类.重写其方法run() .    然后new之.调用Start()方法 1 public class TestThread 2 { 3 private int i; 4 public static void main(String[] args) 5 { 6 // T

Java 多线程之 Runnable VS Thread 以及资源共享问题

对于 Java 多线程编程中的 implements Runnable 与 extends Thread,部分同学可能会比较疑惑,它们之间究竟有啥区别和联系呢?他们是不是没啥区别随便选呢?实际中究竟该选择哪一个呢? 甚至网上不少博客文章以讹传讹得出不少谬论,那今天的走进科学栏目将带您一一揭开谜底. 1.区别: 其实这块主要是围绕着接口和抽象类的区别以及一些设计原则而言的. 1.1 Inheritance Option: The limitation with "extends Thread&qu

JAVA多线程Thread VS Runnable详解

要求 必备知识 本文要求基本了解JAVA编程知识. 开发环境 windows 7/EditPlus 演示地址 源文件 进程与线程 进程是程序在处理机中的一次运行.一个进程既包括其所要执行的指令,也包括了执行指令所需的系统资源,不同进程所占用的系统资源相对独立.所以进程是重量级的任务,它们之间的通信和转换都需要操作系统付出较大的开销. 线程是进程中的一个实体,是被系统独立调度和分派的基本单位.线程自己基本上不拥有系统资源,但它可以与同属一个进程的其他线程共享进程所拥有的全部资源.所以线程是轻量级的

java 线程 --- Thread,Runnable,Callable 基础学习

java 使用 Thread 类代表线程,所有现场对象都必须是 Thread 类或者其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流.java 使用线程执行体来代表这段程序流. 1.继承Thread 类创建线程 启动多线程的步骤如下: (1)定义Thread 类的子类,并重写该类的run() 方法,该run() 方法的方法体就代表类线程需要完成的任务.因此把run() 方法称为线程执行体. (2)创建 Thread 子类的实例,即创建线程对象. (3)调用线程的star()

Java 多线程——Thread类和Runable接口

在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限, 下面看例子: [java] view plaincopy package org.thread.demo; class MyThread extends Thread{ private String name; public

Java多线程——Thread的native底层实现

Java多线程 当我们去阅读java的Thread类的时候,会发现这个类与大部分的java类库API有着明显的差别,它的所有关键方法都被声明为native. native本身指代的就是本地方法,而又由于java线程模型采用基于操作系统原生线程模型,这里默认Thread中native方式代指的是Native POSIX Thread Library. 线程的实现方式有三种:分别是内核线程实现(1:1实现),使用用户线程实现(1:N),使用用户线程加轻量级进程混合实现(N:M实现).而Java从1.