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) + "--------------");
    }
}

在这里插入图片描述

posted @ 2022-02-09 19:44  soberw-  阅读(891)  评论(0编辑  收藏  举报