JUC手写多线程的题目小结

Posted xdcat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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();
    }
}

 

 

 

 

以上是关于JUC手写多线程的题目小结的主要内容,如果未能解决你的问题,请参考以下文章

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

JUC高级多线程_01:基础知识回顾

JUC高级多线程_02:线程间的通信

006-多线程-JUC线程池-并发测试程序

多线程进阶=;JUC编程

Java---JUC并发篇(多线程详细版)