Java多線程經典案例分享


案例一

實現一個容器,提供兩個方法,add(),count() 寫兩個線程,線程1添加10個元素到容器中,線程2實現監控元素的個數,當個數到5個時,線程2給出提示並結束。
本案例我通過閉鎖(也叫門栓鎖)實現,實現如下:

package day_12_28.zuoye;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/** * @author soberw * @Classname AddAndCount * @Description 實現一個容器,提供兩個方法,add,count 寫兩個線程, * 線程1添加10個元素到容器中,線程2實現監控元素的個數, * 當個數到5個時,線程2給出提示並結束。 * @Date 2021-12-28 10:45 */
public class AddAndCount {
    CountDownLatch cdl = new CountDownLatch(1);
    List<String> list = new ArrayList<>();

    public static void main(String[] args) {
        var aac = new AddAndCount();
        new Thread(aac::add, "A").start();
        new Thread(aac::count, "B").start();
    }

    void add() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String item = String.format("%s - %d", "item", i);
            list.add(item);
            System.out.println(Thread.currentThread().getName() + ":" + item);
            if (i == 4) {
                cdl.countDown();
            }
        }

    }

    void count() {
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("程序結束...");
        System.exit(0);
    }
}

在這里插入圖片描述

案例二

編寫程序模擬死鎖。
死鎖,簡單來說就是兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。
下面我就模擬這一狀態:

package day_12_28.zuoye;

/** * @author soberw * @Classname Deadlock * @Description 編寫程序模擬死鎖 * @Date 2021-12-28 10:59 */
public class Deadlock {
    private final Object o1 = new Object();
    private final Object o2 = new Object();

    public static void main(String[] args) {
        Deadlock d = new Deadlock();
        new Thread(d::m1).start();
        new Thread(d::m2).start();
    }

    void m1(){
        System.out.println(Thread.currentThread().getName() + "啟動等待...");
        synchronized(o1){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized(o2){
                System.out.println("哈哈..");
            }
        }
    }

    void m2(){
        System.out.println(Thread.currentThread().getName() + "啟動等待...");
        synchronized(o2){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized(o1){
                System.out.println("哈哈..");
            }
        }
    }

}

在這里插入圖片描述

案例三

編寫程序,實現三個線程,運行輸出 A1 B2 C3 A4 B5 C6 ……
我這里用了兩種方式去實現:
方式一:
用公平鎖:

package day_12_28.zuoye;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/** * @author soberw * @Classname TurnNumber * @Description 編寫程序,實現三個線程,運行輸出 A1 B2 C3 A4 B5 C6 ….. 用公平鎖 * @Date 2021-12-28 14:09 */
public class TurnNumber {
    AtomicInteger num = new AtomicInteger(0);
    private final ReentrantLock rl = new ReentrantLock(true);

    public void show() {
        for (; ; ) {
            rl.lock();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String tn = Thread.currentThread().getName();
            int i = num.incrementAndGet();
            String s = String.format("%s%d", tn, i);
            System.out.print(s + " ");
            if ("C".equals(tn)) {
                System.out.println();
            }
            rl.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TurnNumber tn = new TurnNumber();
        Thread a = new Thread(tn::show, "A");
        Thread b = new Thread(tn::show, "B");
        Thread c = new Thread(tn::show, "C");
        a.setPriority(Thread.MAX_PRIORITY);
        a.start();
        b.setPriority(Thread.NORM_PRIORITY);
        b.start();
        c.setPriority(Thread.MIN_PRIORITY);
        c.start();


    }
}

在這里插入圖片描述
方式二:
用join() 方法

package day_12_28.zuoye;

import java.util.concurrent.atomic.AtomicInteger;

/** * @author soberw * @Classname TurnNumber * @Description 編寫程序,實現三個線程,運行輸出 A1 B2 C3 A4 B5 C6 ….. 第二種寫法,用join() * @Date 2021-12-28 14:09 */
public class TurnNumber2 {
    AtomicInteger num = new AtomicInteger(0);

    public void show() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String tn = Thread.currentThread().getName();
        int i = num.incrementAndGet();
        String s = String.format("%s%d", tn, i);
        System.out.print(s + " ");
        if ("C".equals(tn)) {
            System.out.println();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TurnNumber2 tn = new TurnNumber2();
        while (true) {
            Thread a = new Thread(tn::show, "A");
            Thread b = new Thread(tn::show, "B");
            Thread c = new Thread(tn::show, "C");
            a.setPriority(Thread.MAX_PRIORITY);
            a.start();
            a.join();
            b.setPriority(Thread.NORM_PRIORITY);
            b.start();
            b.join();
            c.setPriority(Thread.MIN_PRIORITY);
            c.start();
            c.join();
        }

    }
}

在這里插入圖片描述

案例四

創建五個線程並進入等待狀態,等兩秒后主線程開始並釋放全部線程,最后主線程結束

本案例我用的是wait() 與notifyAll()組合形式;

package day_12_27;

import java.util.concurrent.TimeUnit;

/** * @author soberw * @Classname WaitAndNotify * @Description 創建五個線程並進入等待狀態,等兩秒后主線程開始並釋放全部線程,最后主線程結束 * @Date 2021-12-27 15:47 */
public class WaitAndNotify {
    public static void main(String[] args) {
        Object co = new Object();

        for (int i = 0; i < 5; i++) {
            MyThread t = new MyThread("Thread" + i, co);
            t.start();
        }

        try {
            TimeUnit.SECONDS.sleep(2);
            System.out.println("-----Main Thread notify-----");
            synchronized (co) {
                //co.notify();
                co.notifyAll();
            }

            TimeUnit.SECONDS.sleep(2);
            System.out.println("Main Thread is end.");

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class MyThread extends Thread {
        private String name;
        private Object co;

        public MyThread(String name, Object o) {
            this.name = name;
            this.co = o;
        }

        @Override
        public void run() {
            System.out.println(name + " is waiting.");
            try {
                synchronized (co) {
                    co.wait();
                }
                System.out.println(name + " has been notified.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在這里插入圖片描述

案例五

用五個線程實現,求123456789 之間放±和100的表達式,如果一個線程求出結果,立即告訴其它停止。

這里我用到了AtomicBoolean原子類來保證數據的原子性:

package day_12_27.zuoye;

import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** * @author soberw * @Classname Number100 * @Description 用五個線程實現,求123456789 之間放+-和100的表達式,如果一個線程求出結果,立即告訴其它停止。 * @Date 2021-12-27 21:14 */
public class Number100 {
    //原子類,保證原子性
    AtomicBoolean ab = new AtomicBoolean(true);

    public void show() {
        String[] ss = {"", "+", "-"};
        StringBuilder sbu = new StringBuilder();
        sbu.append("1");
        Random random = new Random();
        while (ab.get()) {
            for (int i = 2; i < 9; i++) {
                sbu.append(ss[random.nextInt(3)]);
                sbu.append(i);
            }
            Pattern p = Pattern.compile("[0-9]+|-[0-9]+");
            Matcher m = p.matcher(sbu.toString());
            int sum = 0;
            while (m.find()) {
                sum += Integer.parseInt(m.group());
            }
            if (sum == 100) {
                ab.set(false);
                System.out.println(Thread.currentThread().getName() + ":" + sbu.toString() + " = 100");
            }
            sbu.delete(1, sbu.length());
        }
    }

    public static void main(String[] args) {
        var n = new Number100();
        for (int i = 0; i < 5; i++) {
            new Thread(n::show).start();
        }
    }
}

在這里插入圖片描述
在這里插入圖片描述

案例六

模擬經典問題,生產者-消費者問題:
方式一:

package day_12_28.zuoye;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/** * @author soberw * @Classname ProductorAndConsumerForLock * @Description 用線程通信機制解決生產者消費者問題 * @Date 2021-12-28 19:18 */
public class ProductorAndConsumerForLock {

    public static void main(String[] args) {
        Clerk1 clerk1 = new Clerk1();

        Productor1 pro = new Productor1(clerk1);
        Consumer1 con = new Consumer1(clerk1);

        new Thread(pro, "生產者 A").start();
        new Thread(con, "消費者 B").start();

// new Thread(pro, "生產者 C").start();
// new Thread(con, "消費者 D").start();
    }

}

class Clerk1 {
    private int product = 0;

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    // 進貨
    public void get() {
        lock.lock();

        try {
            if (product >= 1) { // 為了避免虛假喚醒,應該總是使用在循環中。
                System.out.println("產品已滿!");

                try {
                    condition.await();
                } catch (InterruptedException e) {
                }

            }
            System.out.println(Thread.currentThread().getName() + " : "
                    + ++product);

            condition.signalAll();
        } finally {
            lock.unlock();
        }

    }

    // 賣貨
    public void sale() {
        lock.lock();

        try {
            if (product <= 0) {
                System.out.println("缺貨!");

                try {
                    condition.await();
                } catch (InterruptedException e) {
                }
            }

            System.out.println(Thread.currentThread().getName() + " : "
                    + --product);

            condition.signalAll();

        } finally {
            lock.unlock();
        }
    }
}

// 生產者
class Productor1 implements Runnable {

    private Clerk1 clerk1;

    public Productor1(Clerk1 clerk1) {
        this.clerk1 = clerk1;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            clerk1.get();
        }
    }
}

// 消費者
class Consumer1 implements Runnable {

    private Clerk1 clerk1;

    public Consumer1(Clerk1 clerk1) {
        this.clerk1 = clerk1;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk1.sale();
        }
    }

}

在這里插入圖片描述

方式二

package day_12_28.zuoye;

/** * @author soberw * @Classname ProducerAndConsumer * @Description 用等待喚醒機制解決生產者消費者問題 * @Date 2021-12-28 16:25 */
public class ProductorAndConsumer {

    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Productor pro = new Productor(clerk);
        Consumer cus = new Consumer(clerk);

        new Thread(pro, "生產者 A").start();
        new Thread(cus, "消費者 B").start();

        new Thread(pro, "生產者 C").start();
        new Thread(cus, "消費者 D").start();
    }

}

//店員
class Clerk {
    private int product = 0;

    //進貨
    public synchronized void get() {//循環次數:0
        //為了避免虛假喚醒問題,應該總是使用在循環中
        while (product >= 1) {
            System.out.println("產品已滿!");

            try {
                this.wait();
            } catch (InterruptedException e) {
            }

        }

        System.out.println(Thread.currentThread().getName() + " : " + ++product);
        this.notifyAll();
    }

    //賣貨
    public synchronized void sale() {//product = 0; 循環次數:0
        while (product <= 0) {
            System.out.println("缺貨!");

            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }

        System.out.println(Thread.currentThread().getName() + " : " + --product);
        this.notifyAll();
    }
}

//生產者
class Productor implements Runnable {
    private Clerk clerk;

    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
            }

            clerk.get();
        }
    }
}

//消費者
class Consumer implements Runnable {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sale();
        }
    }
}

在這里插入圖片描述

案例七

開十個線程打印輸出1~10000中偶數的值,計算總耗時
我采用的是閉鎖機制:

package day_12_28.zuoye;

import java.util.concurrent.CountDownLatch;

/** * @author soberw * @Classname CountTime * @Description 開十個線程打印輸出1~10000中偶數的值,計算總耗時 用閉鎖(門栓) * @Date 2021-12-28 15:22 */
public class CountTime {
    static CountDownLatch cdl = new CountDownLatch(10);

    void show() {
        for (int i = 0; i < 10000; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
        cdl.countDown();
    }

    public static void main(String[] args) {
        CountTime ct = new CountTime();
        long start = System.currentTimeMillis();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 10; i++) {
            new Thread(ct::show).start();
        }
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println((end - start - 100) + "--------------");
    }
}

在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM