• [java多线程]


      负载是一个很大的话题,也是一个非常重要的话题。不管是在大的互联网软件中,还是在一般的小型软件,都对负载有一定的要求,负载过高会导致服务器压力过大;负载过低又比较浪费服务器资源,而且当高请求的时候还可能出现低效率的问题。多线程就是一种提高服务效率的方式。面对海量的用户请求,单线程肯定扛不住,那么多线程的需求也就应运而生,所以说掌握多线程的开发技术对于技术人员来说肯定是非常重要的。参考文档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
  • 相关阅读:
    LevelDB
    Erlang的gen_server的terminate()/2未执行
    集群间心跳检测
    AI从业者关于数学的一些小建议
    《百面机器学习》拾贝----第三章:经典算法
    Demo——Image classification
    《百面机器学习》拾贝----第二章:模型评估
    《百面机器学习》拾贝----第一章:特征工程
    算法工程师---职业生涯规划
    License Plate Detection and Recognition in Unconstrained Scenarios(无约束场景下的车牌检测与识别)
  • 原文地址:https://www.cnblogs.com/liuming1992/p/4764471.html
Copyright © 2020-2023  润新知