【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();
    }
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章