• [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
  • 相关阅读:
    A Node Influence Based Label Propagation Algorithm for Community detection in networks 文章算法实现的疑问
    Fast Newman-FN算法以及模块度定义介绍
    Label Propagation Algorithm LPA 标签传播算法解析及matlab代码实现
    设计一个smartnic
    Intel GEN11 GPU
    Intel GEN9 GPU
    Shared Virtual Memory (SVM) Functions
    connect via ssh to virtualbox guest vm without knowing ip address
    smartnic
    技术精品翻译
  • 原文地址:https://www.cnblogs.com/liuming1992/p/4764471.html
Copyright © 2020-2023  润新知