zoukankan      html  css  js  c++  java
  • java基础-多线程应用案例展示

                          java基础-多线程应用案例展示

                                            作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

    一.两只熊,100只蜜蜂,蜜蜂每次生产的蜂蜜量是1,罐子的容量是30,熊在罐子的蜂蜜量达到20的时候,一次性将蜂蜜吃光。

      1 /*
      2 @author :yinzhengjie
      3 Blog:http://www.cnblogs.com/yinzhengjie/tag/%E5%B0%8F%E8%AF%95%E7%89%9B%E5%88%80/
      4 EMAIL:y1053419035@qq.com
      5 */
      6 package cn.org.yinzhengjie.smallTestBullKnife;
      7 
      8 public class BeeDemo {
      9     public static void main(String[] args) {
     10         Box box = new Box();
     11         Bear b1 = new Bear(box , "熊大");
     12         Bear b2 = new Bear(box , "熊二");
     13         b1.start();
     14         b2.start();
     15         for(int i = 1 ; i <= 100 ; i ++){
     16             new Bee(box , "Bee" + i).start();
     17         }
     18     }
     19 }
     20 
     21 /**
     22  * 罐子
     23  */
     24 class Box{
     25     public static int MAX = 30 ;
     26     private int size = 0 ;
     27 
     28     /**
     29      * 添加蜂蜜方法
     30      */
     31     public synchronized void add(int cap){
     32         while((size + cap) > MAX){
     33             this.notifyAll();
     34             try {
     35                 this.wait();
     36             } catch (InterruptedException e) {
     37                 e.printStackTrace();
     38             }
     39         }
     40         size = size + cap ;
     41         this.notifyAll();
     42     }
     43 
     44     /**
     45      * 清空罐子
     46      */
     47     public synchronized int clear(){
     48         while(size < 20){
     49             this.notifyAll();
     50             try {
     51                 this.wait();
     52             } catch (InterruptedException e) {
     53                 e.printStackTrace();
     54             }
     55         }
     56         int temp = size ;
     57         size = 0 ;
     58         return temp ;
     59     }
     60 }
     61 
     62 /**
     63  * 生产者
     64  */
     65 class Bee extends Thread{
     66     private String beeName ;
     67     private Box box ;
     68     private int  production = 1;
     69     public Bee(Box box ,String name){
     70         this.beeName = name ;
     71         this.box = box ;
     72     }
     73 
     74     public void run() {
     75         while(true){
     76             box.add(production);
     77             System.out.println(beeName + "生产了" + production +"蜂蜜");
     78             try {
     79                 Thread.sleep(50);
     80             } catch (InterruptedException e) {
     81                 e.printStackTrace();
     82             }
     83         }
     84     }
     85 }
     86 
     87 /**
     88  * 消费者
     89  */
     90 class Bear extends Thread{
     91     private String bearName ;
     92     private Box box ;
     93     public Bear(Box box , String name){
     94         this.bearName = name ;
     95         this.box = box ;
     96     }
     97 
     98     public void run() {
     99         while(true){
    100 
    101             int size = box.clear();
    102             System.out.println(bearName + " 吃了【" + size +"】个蜂蜜");
    103         }
    104     }
    105 }

    二.有30个和尚,100个馒头,每个和尚最多吃4馒头,最少一个馒头,满足上述条件下,尽快把馒头吃没,使用多线程模拟,和尚就是线程。

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/%E5%B0%8F%E8%AF%95%E7%89%9B%E5%88%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 package cn.org.yinzhengjie.smallTestBullKnife;
     7 
     8 /**
     9  * 和尚吃馒头问题
    10  */
    11 public class MonkDemo {
    12     public static void main(String[] args) {
    13         Basket b = new Basket();
    14         for(int i = 0 ; i < 30 ; i ++){
    15             new Monk(b , "和尚" + (i+1)+":	").start();
    16         }
    17     }
    18 }
    19 
    20 /**
    21  * 篮子,100个馒头
    22  */
    23 class Basket{
    24     //馒头数量==编号
    25     private int count = 100 ;
    26     //和尚数量 ==没吃馒头的和尚数量
    27     private int numMonks = 30 ;
    28     /**
    29      * 获取馒头的方法,返回馒头的编号
    30      */
    31     public synchronized int getBread(Monk monk){
    32         //和尚第一次吃
    33         if(monk.count == 0){
    34             int temp = count ;
    35             count -- ;
    36             numMonks -- ;
    37             return temp ;
    38         }
    39         //和尚还可以吃的情况
    40         else if(monk.count < Monk.MAX){
    41             //判断是否有多余的馒头
    42             if(count > numMonks){
    43                 int temp = count ;
    44                 count -- ;
    45                 return temp ;
    46             }
    47             else{
    48                 return -1 ;
    49             }
    50         }
    51         return -1 ;
    52     }
    53 }
    54 
    55 /**
    56  * 和尚
    57  */
    58 class Monk extends Thread{
    59     private String monkName ;
    60     private Basket basket ;
    61 
    62     //最少一个馒头
    63     public static int MIN = 1 ;
    64     //最多4个馒头
    65     public static int MAX = 4 ;
    66 
    67     //吃的馒头数
    68     public int count ;
    69 
    70 
    71     public Monk(Basket basket , String monkName){
    72         this.basket = basket ;
    73         this.monkName = monkName ;
    74     }
    75 
    76     public void run() {
    77         while(true){
    78             int no = basket.getBread(this);
    79             if(no ==-1){
    80                 break ;
    81             }
    82             else{
    83                 count ++ ;
    84                 System.out.println(monkName + "吃了编号为[" + no + "]的馒头");
    85             }
    86         }
    87         System.out.println(monkName + "共吃了【" + count + "】馒头");
    88     }
    89 }
      1 和尚2:    吃了编号为[100]的馒头
      2 和尚3:    吃了编号为[99]的馒头
      3 和尚3:    吃了编号为[96]的馒头
      4 和尚3:    吃了编号为[95]的馒头
      5 和尚3:    吃了编号为[94]的馒头
      6 和尚3:    共吃了【4】馒头
      7 和尚4:    吃了编号为[97]的馒头
      8 和尚4:    吃了编号为[93]的馒头
      9 和尚4:    吃了编号为[92]的馒头
     10 和尚4:    吃了编号为[91]的馒头
     11 和尚4:    共吃了【4】馒头
     12 和尚2:    吃了编号为[98]的馒头
     13 和尚2:    吃了编号为[90]的馒头
     14 和尚2:    吃了编号为[89]的馒头
     15 和尚2:    共吃了【4】馒头
     16 和尚6:    吃了编号为[88]的馒头
     17 和尚6:    吃了编号为[87]的馒头
     18 和尚6:    吃了编号为[86]的馒头
     19 和尚6:    吃了编号为[85]的馒头
     20 和尚6:    共吃了【4】馒头
     21 和尚1:    吃了编号为[84]的馒头
     22 和尚1:    吃了编号为[82]的馒头
     23 和尚8:    吃了编号为[83]的馒头
     24 和尚8:    吃了编号为[80]的馒头
     25 和尚8:    吃了编号为[79]的馒头
     26 和尚8:    吃了编号为[78]的馒头
     27 和尚8:    共吃了【4】馒头
     28 和尚1:    吃了编号为[81]的馒头
     29 和尚1:    吃了编号为[77]的馒头
     30 和尚1:    共吃了【4】馒头
     31 和尚5:    吃了编号为[76]的馒头
     32 和尚5:    吃了编号为[75]的馒头
     33 和尚12:    吃了编号为[74]的馒头
     34 和尚12:    吃了编号为[71]的馒头
     35 和尚12:    吃了编号为[70]的馒头
     36 和尚12:    吃了编号为[69]的馒头
     37 和尚12:    共吃了【4】馒头
     38 和尚14:    吃了编号为[68]的馒头
     39 和尚14:    吃了编号为[67]的馒头
     40 和尚14:    吃了编号为[66]的馒头
     41 和尚5:    吃了编号为[73]的馒头
     42 和尚5:    吃了编号为[64]的馒头
     43 和尚5:    共吃了【4】馒头
     44 和尚14:    吃了编号为[65]的馒头
     45 和尚14:    共吃了【4】馒头
     46 和尚10:    吃了编号为[72]的馒头
     47 和尚10:    吃了编号为[63]的馒头
     48 和尚10:    吃了编号为[62]的馒头
     49 和尚10:    吃了编号为[61]的馒头
     50 和尚10:    共吃了【4】馒头
     51 和尚9:    吃了编号为[60]的馒头
     52 和尚9:    吃了编号为[59]的馒头
     53 和尚7:    吃了编号为[58]的馒头
     54 和尚7:    吃了编号为[56]的馒头
     55 和尚7:    吃了编号为[55]的馒头
     56 和尚11:    吃了编号为[54]的馒头
     57 和尚11:    吃了编号为[52]的馒头
     58 和尚11:    吃了编号为[51]的馒头
     59 和尚9:    吃了编号为[57]的馒头
     60 和尚9:    吃了编号为[48]的馒头
     61 和尚9:    共吃了【4】馒头
     62 和尚11:    吃了编号为[50]的馒头
     63 和尚11:    共吃了【4】馒头
     64 和尚7:    吃了编号为[53]的馒头
     65 和尚15:    吃了编号为[45]的馒头
     66 和尚15:    吃了编号为[44]的馒头
     67 和尚15:    吃了编号为[42]的馒头
     68 和尚15:    吃了编号为[41]的馒头
     69 和尚15:    共吃了【4】馒头
     70 和尚17:    吃了编号为[46]的馒头
     71 和尚17:    吃了编号为[39]的馒头
     72 和尚19:    吃了编号为[38]的馒头
     73 和尚19:    吃了编号为[36]的馒头
     74 和尚19:    吃了编号为[35]的馒头
     75 和尚19:    吃了编号为[34]的馒头
     76 和尚19:    共吃了【4】馒头
     77 和尚13:    吃了编号为[47]的馒头
     78 和尚13:    吃了编号为[33]的馒头
     79 和尚13:    吃了编号为[32]的馒头
     80 和尚13:    吃了编号为[31]的馒头
     81 和尚13:    共吃了【4】馒头
     82 和尚20:    吃了编号为[49]的馒头
     83 和尚20:    吃了编号为[30]的馒头
     84 和尚20:    吃了编号为[29]的馒头
     85 和尚20:    吃了编号为[28]的馒头
     86 和尚20:    共吃了【4】馒头
     87 和尚22:    吃了编号为[26]的馒头
     88 和尚22:    吃了编号为[25]的馒头
     89 和尚22:    吃了编号为[23]的馒头
     90 和尚22:    吃了编号为[22]的馒头
     91 和尚22:    共吃了【4】馒头
     92 和尚17:    吃了编号为[37]的馒头
     93 和尚17:    吃了编号为[20]的馒头
     94 和尚17:    共吃了【4】馒头
     95 和尚18:    吃了编号为[40]的馒头
     96 和尚18:    吃了编号为[19]的馒头
     97 和尚18:    吃了编号为[18]的馒头
     98 和尚18:    吃了编号为[17]的馒头
     99 和尚18:    共吃了【4】馒头
    100 和尚25:    吃了编号为[16]的馒头
    101 和尚27:    吃了编号为[15]的馒头
    102 和尚27:    吃了编号为[13]的馒头
    103 和尚16:    吃了编号为[43]的馒头
    104 和尚16:    吃了编号为[11]的馒头
    105 和尚16:    吃了编号为[10]的馒头
    106 和尚16:    吃了编号为[8]的馒头
    107 和尚16:    共吃了【4】馒头
    108 和尚26:    吃了编号为[7]的馒头
    109 和尚7:    共吃了【4】馒头
    110 和尚26:    吃了编号为[6]的馒头
    111 和尚26:    吃了编号为[4]的馒头
    112 和尚26:    吃了编号为[3]的馒头
    113 和尚26:    共吃了【4】馒头
    114 和尚29:    吃了编号为[5]的馒头
    115 和尚30:    吃了编号为[2]的馒头
    116 和尚28:    吃了编号为[9]的馒头
    117 和尚28:    共吃了【1】馒头
    118 和尚27:    吃了编号为[12]的馒头
    119 和尚27:    共吃了【3】馒头
    120 和尚25:    吃了编号为[14]的馒头
    121 和尚25:    共吃了【2】馒头
    122 和尚24:    吃了编号为[21]的馒头
    123 和尚24:    共吃了【1】馒头
    124 和尚23:    吃了编号为[24]的馒头
    125 和尚21:    吃了编号为[27]的馒头
    126 和尚21:    共吃了【1】馒头
    127 和尚23:    共吃了【1】馒头
    128 和尚30:    共吃了【1】馒头
    129 和尚29:    吃了编号为[1]的馒头
    130 和尚29:    共吃了【2】馒头
    以上代码输出结果戳这里

    三.(熊吃蜂蜜升级版本)两只熊,100只蜜蜂,蜜蜂每次生产的蜂蜜量是1到5不等,罐子的容量是30,熊在罐子的蜂蜜量达到20的时候,一次性将蜂蜜吃光,蜜蜂向罐子中添加尽可能的蜂蜜,如果有剩余的话,下次继续添加剩余的量。

      1 /*
      2 @author :yinzhengjie
      3 Blog:http://www.cnblogs.com/yinzhengjie/tag/%E5%B0%8F%E8%AF%95%E7%89%9B%E5%88%80/
      4 EMAIL:y1053419035@qq.com
      5 */
      6 package cn.org.yinzhengjie.smallTestBullKnife;
      7 
      8 import java.util.Random;
      9 
     10 public class BeeproDemo {
     11     public static void main(String[] args) {
     12         BoxPro box = new BoxPro();
     13         Bear b1 = new Bear(box , "熊大");
     14         Bear b2 = new Bear(box , "熊二");
     15         b1.start();
     16         b2.start();
     17         for(int i = 1 ; i <= 100 ; i ++){
     18             new BeePro(  "Bee" + i,box).start();
     19         }
     20     }
     21 }
     22 
     23 /**
     24  * 罐子
     25  */
     26 class BoxPro{
     27     //定义管子容量的最大值为30
     28     public static int MAX = 30 ;
     29     //定义当前管子的容量
     30     private int size = 0 ;
     31 
     32     /**
     33      * 添加蜂蜜方法
     34      */
     35     public synchronized void add(int cap) {
     36         //判断添加的蜂蜜是否会使得管子变满
     37         if (cap > (MAX - size)){
     38             //获取添加蜂蜜多出的量
     39             int remain = cap + size -MAX;
     40             //如果添加的密封会是管子溢出的话,我们直接把罐子加满即可!
     41             size = MAX;
     42             //加满罐子后通知其他线程来消费,并让当前线程进入等待队列
     43             this.notifyAll();
     44             try {
     45                 this.wait();
     46                 Thread.sleep(500);
     47             } catch (Exception e) {
     48                 e.printStackTrace();
     49             }
     50             //如果当前线程被唤醒后,我们需要将之前剩余量继续进行添加操作!
     51             add(remain);
     52         }
     53         //如果当前的蜂蜜不能使罐子盛满,我们就直接添加蜂蜜即可!
     54         size+=cap;
     55         //加完之后需要通知其他线程
     56         this.notifyAll();
     57     }
     58 
     59     /**
     60      * 清空罐子
     61      */
     62     public synchronized int clear(){
     63         while(size < 20){
     64             this.notifyAll();
     65             try {
     66                 this.wait();
     67             } catch (InterruptedException e) {
     68                 e.printStackTrace();
     69             }
     70         }
     71         int temp = size ;
     72         size = 0 ;
     73         return temp ;
     74     }
     75 }
     76 
     77 /**
     78  * 生产者
     79  */
     80 class BeePro extends Thread{
     81     private String beeName ;
     82     private BoxPro box ;
     83     public BeePro(String name,BoxPro box){
     84         this.beeName = name ;
     85         this.box = box ;
     86     }
     87 
     88     public void run() {
     89         Random r = new Random();
     90         while(true){
     91             int production =r.nextInt(5) + 1;
     92             box.add(production);
     93             System.out.println(beeName + "生产了" + production +"蜂蜜");
     94         }
     95     }
     96 }
     97 
     98 /**
     99  * 消费者
    100  */
    101 class Bear extends Thread{
    102     private String bearName ;
    103     private BoxPro box ;
    104     public Bear(BoxPro box , String name){
    105         this.bearName = name ;
    106         this.box = box ;
    107     }
    108 
    109     public void run() {
    110         while(true){
    111             int size = box.clear();
    112             System.out.println(bearName + " 吃了【" + size +"】个蜂蜜");
    113         }
    114     }
    115 }

    四.两个售票员一起买100000张票,使用两种加锁方式(synchronize | ReentrantLock),看性能比对。

      1 /*
      2 @author :yinzhengjie
      3 Blog:http://www.cnblogs.com/yinzhengjie/tag/%E5%B0%8F%E8%AF%95%E7%89%9B%E5%88%80/
      4 EMAIL:y1053419035@qq.com
      5 */
      6 package cn.org.yinzhengjie.smallTestBullKnife;
      7 
      8 import java.util.concurrent.locks.ReentrantLock;
      9 
     10 public class SaleDemo {
     11     public static void main(String[] args) throws InterruptedException {
     12         TicketPool pool1 = new TicketPool();
     13         Thread[] ts = new Thread[4];
     14         long start = System.currentTimeMillis();
     15         for (int i=0;i<4;i++){
     16             Saler yzj = new Saler("yinzhengjie" + i, pool1, true);
     17             ts[i] = yzj;
     18             yzj.start();
     19         }
     20         for (Thread t : ts) {
     21             t.join();
     22         }
     23         long end = System.currentTimeMillis();
     24         System.out.printf("传统(normal)买票方式用时为:[%d]
    ",(end-start));
     25 
     26 
     27         TicketPool pool2 = new TicketPool();
     28         start = System.currentTimeMillis();
     29         for (int i=0;i<4;i++){
     30             Saler yzj = new Saler("yinzhengjie" + i, pool2, false);
     31             ts[i] = yzj;
     32             yzj.start();
     33         }
     34         for (Thread t : ts) {
     35             t.join();
     36         }
     37         end = System.currentTimeMillis();
     38         System.out.printf("轻量级(light)买票方式用时为:[%d]
    ",(end-start));
     39 
     40     }
     41 }
     42 
     43 /**
     44  * 定义票池
     45  */
     46 class TicketPool{
     47     private int Tickets = 100000;
     48 
     49 
     50     /**
     51      * 定义传统synchronized方式买票
     52      */
     53     public  int  doGetTickets1(){
     54         //判断是否符合买票的规则,如果票已经卖完了,就直接返回0.
     55         if (Tickets <= 0){
     56             return 0;
     57         }
     58         //使用synchronized方法同步代码块,保证原子性!
     59         synchronized(this){
     60             //定义当前票数的编号变量temp
     61             int temp = Tickets;
     62             //如果卖出去一张票,就将票数自减1.
     63             Tickets--;
     64             return temp;
     65         }
     66     }
     67 
     68     ReentrantLock lock = new ReentrantLock();
     69     public  int  doGetTickets2(){
     70         //判断是否符合买票的规则,如果票已经卖完了,就直接返回0.
     71         if (Tickets <= 0){
     72             return 0;
     73         }
     74         //上锁,知道写锁的代码块,同样也是保证原子性!
     75         lock.lock();
     76         //定义当前票数的编号变量temp
     77         int temp = Tickets;
     78         //如果卖出去一张票,就将票数自减1.
     79         Tickets--;
     80         //解锁
     81         lock.unlock();
     82         return temp;
     83     }
     84 }
     85 
     86 /**
     87  * 定义售票员类
     88  */
     89 class Saler extends Thread{
     90     private String saleName;
     91     private TicketPool pool;
     92     private boolean normal;
     93     /**
     94      *
     95      * @param saleName      //制定和售票员名称
     96      * @param pool          //指定票池
     97      * @param normal        //是都使用传统方式买票
     98      */
     99     public Saler(String saleName,TicketPool pool,boolean normal){
    100         this.saleName = saleName;
    101         this.pool = pool;
    102         this.normal = normal;
    103     }
    104 
    105     public void run() {
    106         while (true){
    107             int num = normal ? pool.doGetTickets1():pool.doGetTickets2();
    108             if (num == 0){
    109                 return;
    110             }
    111 //            System.out.printf("售票员[%s]出售了第【%d】票
    ",saleName,num);
    112 
    113         }
    114 
    115     }
    116 }
    117 
    118 /*
    119 以上代码输出结果如下:
    120 传统(normal)买票方式用时为:[9]
    121 轻量级(light)买票方式用时为:[8]
    122  */

     

    五.编写socket通信的MyServer,使用分线程完成和每个client的通信。

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/%E5%B0%8F%E8%AF%95%E7%89%9B%E5%88%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 package cn.org.yinzhengjie.socket;
     7 
     8 import java.io.OutputStream;
     9 import java.net.InetSocketAddress;
    10 import java.net.ServerSocket;
    11 import java.net.Socket;
    12 
    13 public class MyServer {
    14     public static void main(String[] args) throws Exception {
    15         //服务器套接字
    16         ServerSocket ss = new ServerSocket(8888) ;
    17         while(true){
    18             //接受连接,
    19             System.out.println("正在接受连接.....");
    20             Socket sock = ss.accept();
    21             new CommThread(sock).start();
    22         }
    23     }
    24 }
    25 
    26 /**
    27  * 服务器和每个客户端的通信线程
    28  */
    29 class CommThread extends Thread{
    30     private Socket sock;
    31 
    32     public CommThread(Socket sock){
    33         this.sock = sock ;
    34     }
    35 
    36     public void run() {
    37         try {
    38             //获取远程地址和端口
    39             InetSocketAddress addr = (InetSocketAddress) sock.getRemoteSocketAddress();
    40             int port = addr.getPort();
    41             String ip = addr.getAddress().getHostAddress();
    42             System.out.printf("有人连接进来了!! : %s , %d
    ", ip, port);
    43 
    44             //向客户端发送消息
    45             int index = 0;
    46             OutputStream out = sock.getOutputStream();
    47             while (true) {
    48                 index ++ ;
    49                 out.write(("yinzhengjie" + index + "
    ").getBytes());
    50                 out.flush();
    51                 Thread.sleep(1000);
    52             }
    53         } catch (Exception e) {
    54             e.printStackTrace();
    55         }
    56     }
    57 }

      需要启动上述代码的服务端,才能用客户端进行连接操作  

    1>.使用java编写的客户端连接服务端

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/%E5%B0%8F%E8%AF%95%E7%89%9B%E5%88%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 package cn.org.yinzhengjie.socket;
     7 
     8 import java.io.BufferedReader;
     9 import java.io.InputStream;
    10 import java.io.InputStreamReader;
    11 import java.net.Socket;
    12 
    13 public class MyClient {
    14     public static void main(String[] args) throws Exception {
    15         Socket s = new Socket("www.yinzhengjie.org.cn" ,8888) ;
    16         System.out.println("连接到服务器了!!");
    17         InputStream in = s.getInputStream();
    18         BufferedReader br = new BufferedReader(new InputStreamReader(in)) ;
    19         String line = null ;
    20         //获取服务端发来的消息
    21         while((line = br.readLine())!= null){
    22             System.out.println("收到消息 : " + line);
    23         }
    24     }
    25 }
    MyClient.java 文件内容

      测试结果如下:

      2>.使用Windows自带的telnet客户端连接服务端

     

      查看接收的数据信息如下:

      3>.使用xshell客户端连接服务端

      综上所述,有三个端连接了服务端,我们可以查看服务端的输出数据如下:

       上述的解决方案当客户端数量过多的话,最终可能会存在资源耗尽的情况,建议使用NIO技术,详情请参考:https://www.cnblogs.com/yinzhengjie/p/9257142.html。

  • 相关阅读:
    vue 中简单路由的实现
    Vue中对生命周期的理解
    内存泄漏
    前端工程化
    exports 和 module.exports 的区别
    Nodejs的url模块方法
    MongoDB 的获取和安装
    Anjular JS 的一些运用
    移动端vconsole调试
    安装fiddler时,电脑浏览器没网
  • 原文地址:https://www.cnblogs.com/yinzhengjie/p/9255629.html
Copyright © 2011-2022 走看看