• 【JUC】手写多线程的题目小结


    简单的线程池,体现线程的复用

    不使用Executors.newFixedThreadPool(int)、Executors.newSingleThreadExecutor()、Executors.newCachedThreadPool(),而是通过ThreadPoolExecutor的7个参数的构造函数来创建线程池。不使用的原因写在:https://www.cnblogs.com/xdcat/p/12981188.html

     1     public static void selfThreadPool() {
     2         Runtime.getRuntime().availableProcessors();
     3         ExecutorService threadPool = new ThreadPoolExecutor(
     4                 2,//corePoolSize
     5                 5,//maximumPoolSize
     6                 1L,//keepAliveTime
     7                 TimeUnit.SECONDS,new LinkedBlockingDeque<>(3),
     8                 Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
     9         try {
    10             for (int i = 1; i <= 10; i++) {
    11                 final int tmp = i;
    12                 threadPool.execute(()->{
    13                     System.out.println(Thread.currentThread().getName()+"线程"+",执行任务"+tmp);
    14                 });
    15             }
    16         }catch (Exception e){
    17             e.printStackTrace();
    18         }finally {
    19             threadPool.shutdown();
    20         }
    21     }

    输出结果

    pool-2-thread-1执行任务0
    pool-2-thread-4执行任务3
    pool-2-thread-1执行任务5
    pool-2-thread-2执行任务1
    pool-2-thread-3执行任务2
    pool-2-thread-2执行任务8
    pool-2-thread-1执行任务7
    pool-2-thread-4执行任务6
    pool-2-thread-5执行任务4
    pool-2-thread-3执行任务9
    View Code

    消费者和生产者模式

    使用传统的锁来实现,还可以通过阻塞队列实现,阻塞队列的实现见https://www.cnblogs.com/xdcat/p/12958057.html

     1 /**
     2  * 一个初始值为零的变量,两个线程对其交替操作,一个加1一个减1,
     3  */
     4 class Cakes {
     5     private int cakeNumber = 0;
     6     private Lock lock = new ReentrantLock();
     7     private Condition condition = lock.newCondition();
     8     public void increment() throws InterruptedException {
     9         lock.lock();
    10         try{
    11             //判断 (多线程判断用while)
    12             while(cakeNumber != 0){
    13                 //等待 不能生产
    14                 condition.await();
    15             }
    16             //进行操作(生产蛋糕)
    17             cakeNumber++;
    18             System.out.println(Thread.currentThread().getName()+"烹饪" + cakeNumber+"个蛋糕");
    19             //通知唤醒
    20             condition.signalAll();
    21         }catch(Exception e){
    22             e.printStackTrace();
    23         }finally{
    24             lock.unlock();
    25         }
    26     }
    27 
    28     public void decrement() throws InterruptedException {
    29         lock.lock();
    30         try{
    31             //判断 (多线程判断用while)
    32             while(cakeNumber ==0){
    33                 //等待 不能消费
    34                 condition.await();
    35             }
    36             //进行操作
    37             cakeNumber--;
    38             System.out.println(Thread.currentThread().getName()+"吃完蛋糕,还剩" + cakeNumber+"个蛋糕");
    39             //通知唤醒
    40             condition.signal();
    41         }catch(Exception e){
    42             e.printStackTrace();
    43         }finally{
    44             lock.unlock();
    45         }
    46     }
    47 }
    48 public class ProdConsumerTraditionDemo {
    49     public static void main(String[] args) {
    50         Cakes cake = new Cakes();
    51         new Thread(()->{
    52             for (int i = 0; i < 5; i++) {
    53                 try {
    54                     cake.increment();
    55                 } catch (InterruptedException e) {
    56                     e.printStackTrace();
    57                 }
    58             }
    59         },"厨师").start();
    60         new Thread(()->{
    61             for (int i = 0; i < 5; i++) {
    62                 try {
    63                     cake.decrement();
    64                 } catch (InterruptedException e) {
    65                     e.printStackTrace();
    66                 }
    67             }
    68         },"顾客").start();
    69     }
    70 }

    实现自旋锁

    尝试获取锁的线程不会阻塞,而是采用循环的方式去获取锁,好处是减少了线程上下文切换的消耗,缺点是循环会消耗CPU。

     1 public class SpinLockDemo {
     2     //原子引用线程
     3     AtomicReference<Thread> atomicReference = new AtomicReference<>();
     4 
     5     public void myLock(){
     6         Thread thread = Thread.currentThread(); 
    8
    while(!atomicReference.compareAndSet(null,thread)){ 9 //匹配则不进入循环 获取锁后!=null进入循环 释放锁后被set为null退出循环
    16 }
    18 } 19 20 public void myUnlock(){ 21 Thread thread = Thread.currentThread(); 22 atomicReference.compareAndSet(thread,null);
    24 } 25 public static void main(String[] args) { 26 SpinLockDemo spinLockDemo = new SpinLockDemo(); 27 new Thread(()->{ 28 spinLockDemo.myLock();
    35 spinLockDemo.myUnlock(); 36 },"A").start();
    42 new Thread(()->{ 43 spinLockDemo.myLock();
    50 spinLockDemo.myUnlock(); 51 },"B").start(); 52 } 53 }

    实现阻塞队列

     1 public class MyBlockQueue {
     2     private List<Integer> queue = new ArrayList<>();//用数组实现的话定义索引变量就可以
     3     private volatile int curSize;
     4     private volatile int capacity;
     5     private Lock lock = new ReentrantLock();
     6     private final Condition notFull = lock.newCondition();//不满
     7     private final Condition notNull = lock.newCondition();//不空
     8 
     9     public MyBlockQueue(int capacity) {
    10         this.capacity = capacity;
    11     }
    12 
    13     public void add(int value){
    14         lock.lock();
    15         try{
    16             while(curSize == capacity){
    17                 //等待队列不满
    18                 notFull.await();
    19             }
    20             queue.add(value);
    21             ++curSize;
    22 //            System.out.println("入队成功");
    23             notNull.signal();//通知队列不为空
    24         }catch(Exception e){
    25             e.printStackTrace();
    26         }finally{
    27             lock.unlock();
    28         }
    29     }
    30 
    31     public Integer take(){
    32         lock.lock();
    33         Integer x = null;
    34         try{
    35             while(curSize == 0){
    36                 //等待队列不为空
    37                 notNull.await();
    38             }
    39             x = queue.remove(0);
    40             curSize--;
    41             notFull.signal();
    42         }catch(Exception e){
    43             e.printStackTrace();
    44         }finally{
    45             lock.unlock();
    46         }
    47         return x;
    48     }
    49 
    50     public static void main(String[] args) {
    51         MyBlockQueue queue = new MyBlockQueue(5);
    52         new Thread(()->{
    53             for (int i = 0; i < 10; i++) {
    54                 System.out.println(Thread.currentThread().getName()+"消费"+queue.take());
    55             }
    56         }).start();
    57         new Thread(()->{
    58             for (int i = 0; i < 10; i++) {
    59                 queue.add(i);
    60                 System.out.println(Thread.currentThread().getName()+"生产"+i);
    61             }
    62 
    63         }).start();
    64     }
    65 }

    多线程交替打印ABC

     1 import java.util.concurrent.locks.Condition;
     2 import java.util.concurrent.locks.Lock;
     3 import java.util.concurrent.locks.ReentrantLock;
     4 
    10 class Plat{
    11     private int id = 1; // 编号
    12     private Lock lock = new ReentrantLock();
    13     private Condition a = lock.newCondition();
    14     private Condition b = lock.newCondition();
    15     private Condition c = lock.newCondition();
    16     public void printA(){
    17         lock.lock();
    18         try{
    19             while (id != 1){
    20                 a.await();
    21             }
    22             System.out.println("A");
    23             id = 2;
    24             b.signal();
    25         }catch(Exception e){
    26             e.printStackTrace();
    27         }finally{
    28             lock.unlock();
    29         }
    30     }
    31     public void printB(){
    32         lock.lock();
    33         try{
    34             while (id != 2){
    35                 b.await();
    36             }
    37             System.out.println("B");
    38             id = 3;
    39             c.signal();
    40         }catch(Exception e){
    41             e.printStackTrace();
    42         }finally{
    43             lock.unlock();
    44         }
    45     }
    46     public void printC(){
    47         lock.lock();
    48         try{
    49             while (id != 3){
    50                 c.await();
    51             }
    52             System.out.println("C");
    53             id = 1;
    54             a.signal();
    55         }catch(Exception e){
    56             e.printStackTrace();
    57         }finally{
    58             lock.unlock();
    59         }
    60     }
    61 
    62 }
    63 public class PrintAbc {
    64     public static void main(String[] args) throws InterruptedException {
    65         Plat plat = new Plat();
    66         for (int i = 0; i < 3; i++) {
    67             new Thread(()->{
    68                 plat.printA();
    69             }).start();
    70             new Thread(()->{
    71                 plat.printB();
    72             }).start();
    73             new Thread(()->{
    74                 plat.printC();
    75             }).start();
    76         }
    77     }
    78 }

    两个线程实现交叉打印1-10000

    同步代码块实现

     1 public class PrintOneThousand {
     2     private static volatile Integer counter = 0;
     3     private static Object monitor = new Object();
     4 
     5     public static void main(String[] args) {
     6         new Thread(()->{
     7             while (true){
     8                 synchronized (monitor){
     9                     if (counter % 2 != 0){
    10                         continue;
    11                     }
    12                     int i = ++counter;
    13                     if (i > 1000){
    14                         return;
    15                     }
    16                     System.out.println("奇数线程:"  + i);
    17                     try {
    18                         monitor.notify();
    19                         monitor.wait();
    20                     } catch (InterruptedException e) {
    21                         e.printStackTrace();
    22                     }
    23                 }
    24             }
    25         }).start();
    26 
    27         new Thread(()->{
    28             while (true){
    29                 synchronized (monitor){
    30                     if (counter % 2 == 0){
    31                         continue;
    32                     }
    33                     int i = ++counter;
    34                     if (i > 1000){
    35                         return;
    36                     }
    37                     System.out.println("偶数线程:"  + i);
    38                     try {
    39                         monitor.notify();
    40                         monitor.wait();
    41                     } catch (InterruptedException e) {
    42                         e.printStackTrace();
    43                     }
    44                 }
    45             }
    46         }).start();
    47     }
    48 }

    volatitle实现

    public class PrintOneThousand{
        private static volatile  boolean loopForOdd = true;
        private static volatile  boolean loopForEven = true;
        private static volatile int counter = 1;
        private static boolean flag = true;
    
        public static void main(String[] args) throws InterruptedException {
            // 先启动奇数线程
            loopForOdd = false;
            new Thread(()->{
                while (flag) {
                    while (loopForOdd) {
    
                    }
                    int counter = PrintOneThousand.counter;
                    if (counter > 100) {
                        flag=false;
                        break;
                    }
                    System.out.println("奇数线程:" + counter);
    
                    PrintOneThousand.counter++;
                    // 修改volatile,通知偶数线程停止循环,同时,准备让自己陷入循环
                    loopForEven = false;
                    loopForOdd = true;
                }
            }).start();
    
            new Thread(()->{
                while (flag) {
                    while (loopForEven) {
    
                    }
                    int counter = PrintOneThousand.counter;
                    if (counter > 100) {
                        flag=false;
                        break;
                    }
                    System.out.println("偶数线程:" + counter);
                    PrintOneThousand.counter++;
                    // 修改volatile,通知奇数线程停止循环,同时,准备让自己陷入循环
                    loopForOdd = false;
                    loopForEven = true;
                }
            }).start();
        }
    }

     

  • 相关阅读:
    Day 37 数据库初识
    Day 36 socket并发,协程,进程池与线程池
    Day 35 GIL全局解释器锁,死锁与递归锁,信号量,event事件,线程queue
    DAY 34 进程通信、消费者模型和线程
    09-盒模型
    08-层叠性权重相同处理
    07-css的继承性和层叠性
    06-伪元素选择器
    05-伪类选择器
    04-属性选择器
  • 原文地址:https://www.cnblogs.com/xdcat/p/12996950.html
Copyright © 2020-2023  润新知