• JAVA进阶27(多线程/02)


    1、线程同步

    并发:同一个对象多个线程同步操作

     1 package cn.Thread_demo;
     2 
     3 /**
     4  * @Classname SynBlockTest01
     5  * @Description TODO
     6  * @Date 2019-5-13 12:16
     7  * @Created by Administrator
     8  */
     9 public class SynBlockTest01 {
    10     public static void main(String[] args) {
    11         //一份资源
    12         SynWeb12306 web = new SynWeb12306();
    13         //多个代理
    14         new Thread(web, "张三").start();
    15         new Thread(web, "张四").start();
    16         new Thread(web, "张五").start();
    17     }
    18 }
    19 
    20 class SynWeb12306 implements Runnable {
    21     //票数
    22     private int ticketNums = 10;
    23     private boolean flag = true;
    24 
    25     @Override
    26     public void run() {
    27         while (flag) {
    28             try {
    29                 Thread.sleep(100);
    30             } catch (InterruptedException e) {
    31                 e.printStackTrace();
    32             }
    33             test2();
    34         }
    35     }
    36     public synchronized void test2(){
    37         synchronized (this){
    38             if (ticketNums <= 0) {
    39                 flag = false;
    40                 return;
    41             }
    42         }
    43         //模拟延时
    44         try {
    45             Thread.sleep(100);
    46         } catch (InterruptedException e) {
    47             e.printStackTrace();
    48         }
    49         System.out.println(Thread.currentThread().getName()+"--"+ticketNums--);
    50     }
    51 
    52     //线程不安全, tickNums对象在变
    53     public synchronized void test(){
    54         if (ticketNums <= 0) {
    55             flag = false;
    56             return;
    57         }
    58         //模拟延时
    59         try {
    60             Thread.sleep(200);
    61         } catch (InterruptedException e) {
    62             e.printStackTrace();
    63         }
    64         System.out.println(Thread.currentThread().getName()+"--"+ticketNums--);
    65     }
    66 }
    View Code

    运行图

    2、影院购票模拟

    -----简单版

     1 package cn.Thread_demo;
     2 
     3 import javax.security.auth.login.AccountException;
     4 
     5 /**
     6  * @Classname HappyCinema
     7  * @Description TODO
     8  * @Date 2019-5-14 10:30
     9  * @Created by Administrator
    10  * <p>
    11  * #####选位置
    12  */
    13 public class HappyCinema {
    14     public static void main(String[] args) {
    15         Cinema c = new Cinema(2, "后天");
    16         new Thread(new Customer(c,4),"张三").start();
    17         new Thread(new Customer(c,2),"李四").start();
    18     }
    19 }
    20 
    21 //顾客
    22 class Customer implements Runnable {
    23     Cinema cinema;
    24     int seats;
    25 
    26     public Customer(Cinema cinema, int seats) {
    27         this.cinema = cinema;
    28         this.seats = seats;
    29     }
    30 
    31     @Override
    32     public void run() {
    33         synchronized (cinema) {
    34             boolean flag = cinema.bookTickets(seats);
    35             if (flag) {
    36                 System.out.println("出票成功" + Thread.currentThread().getName() + "位置为:" + seats);
    37             } else {
    38                 System.out.println("出票失败" + Thread.currentThread().getName() + "位置为不够");
    39             }
    40         }
    41     }
    42 }
    43 
    44 //影院
    45 class Cinema {
    46     int available;  //可供选择的位置
    47     String name;    //名称
    48 
    49     public Cinema(int available, String name) {
    50         this.available = available;
    51         this.name = name;
    52     }
    53 
    54     //购票
    55     public boolean bookTickets(int seats) {
    56         System.out.println("可用位置为:" + available);
    57         if (seats > available) {
    58             return false;
    59         }
    60         available -= seats;
    61         return true;
    62     }
    63 }
    View Code

    -----加入容器版

     1 package cn.Thread_demo;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 /**
     7  * @Classname HappyCinema
     8  * @Description TODO
     9  * @Date 2019-5-14 10:30
    10  * @Created by Administrator
    11  * <p>
    12  * #####选位置
    13  */
    14 public class HappyCinema01 {
    15     public static void main(String[] args) {
    16         //可用位置
    17         List<Integer> available = new ArrayList<>();
    18         available.add(1);
    19         available.add(2);
    20         available.add(4);
    21         available.add(5);
    22         available.add(7);
    23 
    24         //顾客需要的位置
    25         List<Integer> seats1 = new ArrayList<>();
    26         seats1.add(1);
    27         seats1.add(2);
    28         List<Integer> seats2 = new ArrayList<>();
    29         seats2.add(3);
    30         seats2.add(7);
    31         HtCinema c = new HtCinema(available,"HtCinema");
    32         new Thread(new HappyCustomer(c, seats1), "张三").start();
    33         new Thread(new HappyCustomer(c, seats2), "李四").start();
    34     }
    35 }
    36 
    37 //顾客
    38 class HappyCustomer implements Runnable {
    39     HtCinema cinema;
    40     List<Integer> seats;
    41 
    42     public HappyCustomer(HtCinema cinema, List<Integer> seats) {
    43         this.cinema = cinema;
    44         this.seats = seats;
    45     }
    46 
    47     @Override
    48     public void run() {
    49         synchronized (cinema) {
    50             boolean flag = cinema.bookTickets(seats);
    51             if (flag) {
    52                 System.out.println("出票成功" + Thread.currentThread().getName() + "位置为:" + seats);
    53             } else {
    54                 System.out.println("出票失败" + Thread.currentThread().getName() + "位置为不够");
    55             }
    56         }
    57     }
    58 }
    59 
    60 //影院
    61 class HtCinema {
    62     List<Integer> available;  //可供选择的位置
    63     String name;    //名称
    64 
    65     public HtCinema(List<Integer> available, String name) {
    66         this.available = available;
    67         this.name = name;
    68     }
    69 
    70     //购票
    71     public boolean bookTickets(List<Integer> seats) {
    72         System.out.println("可用位置为:" + available);
    73         List<Integer> copy = new ArrayList<>();
    74         copy.addAll(available);
    75 
    76         //相减
    77         copy.retainAll(seats);
    78         //判断大小
    79         if (available.size()-copy.size()!=seats.size()){
    80             return false;
    81         }
    82         //成功
    83         available = copy;
    84         return true;
    85     }
    86 }
    View Code

    3、死锁

    过多的同步可能造成相互不释放资源。从而相互等待,一般发生于同步中持有多个对象的锁。

    4、线程协作

    并发协作模型:“生产者/消费者模式”---管程法、信号灯法

    生产者:负责生产数据的模块(这里的模块可能是:方法、对象、线程、进程)

    消费者:负责处理数据的模块(这里的模块可能是:方法、对象、线程、进程)

    缓冲区:消费者不能直接使用生产者的数据,他们之间有个“缓冲区”;生产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要处理的数据。

      1 package cn.Thread_demo;
      2 
      3 /**
      4  * @Classname CoTest01
      5  * @Description TODO
      6  * @Date 2019-5-15 14:16
      7  * @Created by Administrator
      8  * 协作模型:生产者消费者实现方式一:管程法
      9  */
     10 public class CoTest01 {
     11     public static void main(String[] args) {
     12         SynContainer container = new SynContainer();
     13         new Productor(container).start();
     14         new Consumer(container).start();
     15     }
     16 }
     17 
     18 //生产者
     19 class Productor extends Thread {
     20     SynContainer container;
     21 
     22     public Productor(SynContainer container) {
     23         this.container = container;
     24     }
     25 
     26     @Override
     27     public void run() {
     28 //        生产
     29         for (int i = 0; i < 100; i++) {
     30             System.out.println("生产--" + i + "个");
     31             container.push(new Steamedbun(i));
     32         }
     33     }
     34 }
     35 
     36 //消费者
     37 class Consumer extends Thread {
     38     SynContainer container;
     39 
     40     public Consumer(SynContainer container) {
     41         this.container = container;
     42     }
     43 
     44     @Override
     45     public void run() {
     46 //        消费
     47         for (int i = 0; i < 100; i++) {
     48             System.out.println("消费--" + container.pop().id + "个");
     49             container.push(new Steamedbun(i));
     50         }
     51     }
     52 }
     53 
     54 //缓冲区
     55 class SynContainer {
     56     Steamedbun[] buns = new Steamedbun[10];  //存储容器
     57     int count = 0;      //计数器
     58 
     59     //    存储 / 生产
     60     public synchronized void push(Steamedbun bun) {
     61 //        何时能生产---  容器存在空间
     62 //        不能生产---等待
     63         if (count==buns.length){
     64             try {
     65                 this.wait();       //线程阻塞,消费者通知生产解除
     66             } catch (InterruptedException e) {
     67                 e.printStackTrace();
     68             }
     69         }
     70 //        存在空间---  可以生产
     71         buns[count] = bun;
     72         count++;
     73         this.notifyAll();
     74     }
     75 
     76     //    获取 / 消费
     77     public synchronized Steamedbun pop() {
     78 //        何时消费,容器中是否存在数据
     79 //        没有数据---等待
     80         if (count==0){
     81             try {
     82                 this.wait();    //线程阻塞。生产者通知消费时解除
     83             } catch (InterruptedException e) {
     84                 e.printStackTrace();
     85             }
     86         }
     87 //        存在数据---可以消费
     88         count--;
     89         Steamedbun bun = buns[count];
     90         this.notifyAll();
     91         return bun;
     92     }
     93 }
     94 
     95 //数据
     96 class Steamedbun {
     97     int id;
     98 
     99     public Steamedbun(int id) {
    100         this.id = id;
    101     }
    102 }
    View Code
     1 package cn.Thread_demo;
     2 
     3 /**
     4  * @Classname CoTest02
     5  * @Description TODO
     6  * @Date 2019-5-15 14:48
     7  * @Created by Administrator
     8  * 协作模型:生产者消费者实现方式一:信号灯法
     9  * 借助标志位
    10  */
    11 public class CoTest02 {
    12     public static void main(String[] args) {
    13         Tv tv = new Tv();
    14         new Player(tv).start();
    15         new Watch(tv).start();
    16     }
    17 }
    18 
    19 //生产者--演员
    20 class Player extends Thread {
    21     Tv tv;
    22 
    23     public Player(Tv tv) {
    24         this.tv = tv;
    25     }
    26 
    27     @Override
    28     public void run() {
    29         for (int i = 0; i < 20; i++) {
    30             if (i % 2 == 0) {
    31                 this.tv.play("奇葩说");
    32             } else {
    33                 this.tv.play("hello world");
    34             }
    35         }
    36     }
    37 }
    38 
    39 //消费者--观众
    40 class Watch extends Thread {
    41     Tv tv;
    42 
    43     public Watch(Tv tv) {
    44         this.tv = tv;
    45     }
    46 
    47     @Override
    48     public void run() {
    49         for (int i = 0; i < 20; i++) {
    50             tv.watch();
    51         }
    52     }
    53 }
    54 
    55 //同一个资源--电视
    56 class Tv {
    57     String voice;
    58     //信号灯
    59     //T 表示演员表演 观众等待
    60     //F 表示观众观看 演员等待
    61     boolean flag = true;
    62 
    63     //表演
    64     public synchronized void play(String voice) {
    65         //演员等待
    66         if (!flag) {
    67             try {
    68                 this.wait();
    69             } catch (InterruptedException e) {
    70                 e.printStackTrace();
    71             }
    72         }
    73         System.out.println("表演了" + voice);
    74         this.voice = voice;
    75         //唤醒
    76         this.notifyAll();
    77         this.flag = !this.flag;       //切换标志
    78     }
    79 
    80     //观看
    81     public synchronized void watch() {
    82         //观众等待
    83         if (flag) {
    84             try {
    85                 this.wait();
    86             } catch (InterruptedException e) {
    87                 e.printStackTrace();
    88             }
    89         }
    90         //观看
    91         System.out.println("听到了" + voice);
    92         //唤醒
    93         this.notifyAll();
    94         this.flag = !this.flag;   //切换标志
    95     }
    96 }
    View Code

    5、单例模式

     1 package cn.Thread_demo;
     2 
     3 /**
     4  * @Classname DoubleCheckedLocking
     5  * @Description TODO
     6  * @Date 2019-5-16 10:36
     7  * @Created by Administrator
     8  * ---单例模式:套路,在多线程环境下,对外存在一个对象
     9  * 1、构造器私有化--避免外部new构造器
    10  * 2、提供私有的静态属性--存储对象的地址
    11  * 3、提供公共的静态方法--获取属性
    12  */
    13 public class DoubleCheckedLocking {
    14     //    1、构造器私有化
    15     private DoubleCheckedLocking() {
    16 
    17     }
    18 
    19     //    2、提供私有的静态属性(没有volatile,其他线程可能访问一个没有初始化的对象)
    20     private static volatile DoubleCheckedLocking instance;
    21 
    22     //    3、提供公共的静态方法
    23     public static DoubleCheckedLocking getInstance() {
    24         //再次检测
    25         if (null != instance) {    //避免不必要的同步,已经存在对象
    26             return instance;
    27         }
    28         synchronized (DoubleCheckedLocking.class) {
    29             if (null == instance) {
    30                 instance = new DoubleCheckedLocking();
    31             }
    32             return instance;
    33         }
    34     }
    35 
    36     public static void main(String[] args) {
    37         Thread t = new Thread(() -> {
    38             System.out.println(DoubleCheckedLocking.getInstance());
    39         });
    40         t.start();
    41         System.out.println(DoubleCheckedLocking.getInstance());
    42     }
    43 }
    View Code

    运行图

    6、ThreadLocal

    每个线程存储自己的数据,更改不会影响其他线程

     1 package cn.Thread_demo;
     2 
     3 /**
     4  * @Classname ThreadLocalTest01
     5  * @Description TODO
     6  * @Date 2019-5-16 14:17
     7  * @Created by Administrator
     8  * ---ThreadLocal:每个线程自身的存储区域(本地、局部)
     9  * get/set/initialValue
    10  */
    11 public class ThreadLocalTest01 {
    12 //    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
    13 //    更改初始化值
    14     private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->200);
    15     public static void main(String[] args) {
    16         //获取值
    17         System.out.println(Thread.currentThread().getName() + "-->" + threadLocal.get());
    18         //设置值
    19         threadLocal.set(199);
    20         System.out.println(Thread.currentThread().getName() + "-->" + threadLocal.get());
    21         new Thread(new MyRun()).start();
    22     }
    23     public static class MyRun implements Runnable{
    24         @Override
    25         public void run() {
    26             threadLocal.set((int)(Math.random()*99));
    27             System.out.println(Thread.currentThread().getName() + "-->" + threadLocal.get());
    28         }
    29     }
    30 }
    View Code

    运行图

    7、可重入锁:锁可以延续使用

     1 package cn.Thread_demo;
     2 
     3 /**
     4  * @Classname LockTest
     5  * @Description TODO
     6  * @Date 2019-5-16 15:14
     7  * @Created by Administrator
     8  *     可重入锁:锁可以延续使用
     9  */
    10 public class LockTest {
    11     public void test(){
    12         //第一次获得锁
    13         synchronized (this){
    14             while (true){
    15                 //第二次获得同样的锁
    16                 synchronized (this){
    17                     System.out.println("ReentrantLock!");
    18                 }
    19                 try {
    20                     Thread.sleep(1000);
    21                 } catch (InterruptedException e) {
    22                     e.printStackTrace();
    23                 }
    24             }
    25         }
    26     }
    27 
    28     public static void main(String[] args) {
    29         new LockTest().test();
    30     }
    31 }
    View Code

    运行图

    8、JUC

  • 相关阅读:
    菜鸟系列k8s——快速部署k8s集群(3)
    菜鸟系列docker——docker容器(7)
    菜鸟系列Fabric源码学习 — 区块同步
    菜鸟系列Fabric源码学习 — peer节点启动
    菜鸟系列Fabric源码学习 — orderer服务启动
    递归科赫雪花
    汉诺塔递归函数hanoi
    字符串格式化与.format()
    turtle风轮绘制
    接口签名2
  • 原文地址:https://www.cnblogs.com/Anemia-BOY/p/10857710.html
Copyright © 2020-2023  润新知