消费者和生产者问题:

一、传统生产者消费者问题,防止虚假唤醒:(将if改为while)

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9bce7061-fe04-4691-a534-d398180733f6/Untitled.png

public class Demo02 {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();

    }
}

class Data {
    private int num = 0;

    public synchronized void increment() throws InterruptedException {
				//将if改用为while以防止虚假唤醒
        while (num != 0) {
            this.wait();
        }
        num++;
        System.out.println(Thread.currentThread().getName() + "=>" + num);
        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
        while (num == 0) {
            this.wait();
        }
        num--;
        System.out.println(Thread.currentThread().getName() + "=>" + num);
        this.notifyAll();
    }
}

线程不安全

List不安全 的三种解决方式

package cn.juc.unsafe;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author ikart
 * @date 2021年04月17日9:48
 */
public class SafeTest {
    public static void main(String[] args) {
        /**
         * 解决list集合不安全
         * 方式一:List<String> list = new Vector<>();
         * 方式二:List<String> list = Collections.synchronizedList(new ArrayList<>());\\
         * 方式三:List<String> list = new CopyOnWriteArrayList<>(); 使用JUC
         */
        List<String> list = new CopyOnWriteArrayList<>();

        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(1, 5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

Set不安全


package cn.juc.unsafe;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @author ikart
 * @date 2021年04月17日10:21
 */
public class SetUnsafe {
    public static void main(String[] args) {
//        Set<String> set = new HashSet<>(); //线程不安全的
//        Set<String> set = Collections.synchronizedSet(new HashSet<>()); 使用集合工具保证线程安全
        Set<String> set = new CopyOnWriteArraySet<>(new HashSet<>()); 使用JUC保证线程安全
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }
}

Callable

package cn.juc.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author ikart
 * @date 2021年04月17日15:08
 */
public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Phone phone = new Phone();
        //FutureTask适配器
        FutureTask futureTask = new FutureTask<>(phone);

        new Thread(futureTask,"A").start();
        //结果会被缓存,效率高
        new Thread(futureTask,"B").start();

        //这个get可能会导致线程阻塞,要把它放到最后执行,或者使用异步通信的方式解决
        Integer o = (Integer)futureTask.get();
        System.out.println(o);
    }
}

class Phone implements Callable{

    @Override
    public Integer call() throws Exception {
        System.out.println("call()"+ Thread.currentThread().getName());
        return 657;
    }
}

运行结果:

call()A
657

此时开启了两条线程,发现运行的是线程A,证明了结果被缓存了。

CountDownLatch(减法计数器)

package cn.juc.common_util;

import java.util.concurrent.CountDownLatch;

/**
 * 一个减法技术器的测试案例
 * @author ikart
 * @date 2021年04月17日15:54
 */
public class CountDownLatchTest {
    public static void main(String[] args) throws Throwable {
        //减法计数器,给定一个数值,依次往下减
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                System.out.println("Go out "+Thread.currentThread().getName());
                countDownLatch.countDown();
            },String.valueOf(i)).start();
        }

        //当减完后执行后面的操作
        countDownLatch.await();
        System.out.println("Close Door");
    }
}

Cyclic Barrier(加法计数器)

package cn.juc.common_util;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author ikart
 * @date 2021年04月18日11:32
 */
public class CyclicBarrierTest {
    public static void main(String[] args) {
        //当计数器到设定值时,开启一条新线程
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("成功召唤神龙");
        });

        for (int i = 1; i <= 7; i++) {
            //注意局部变量i的作用域
            final int temp = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName()+"获得第"+ temp +"颗龙珠");
                try {
                    //每执行一次,执行+1(从0开始)
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

Semaphore

package cn.juc.common_util;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * @author ikart
 * @date 2021年04月18日13:09
 */
public class SemaphoreTest {
    public static void main(String[] args) {
        //一次最多同时授权许可证
        Semaphore semaphore = new Semaphore(3);

        for (int i = 1; i <= 9; i++) {
            final int temp = i;
            new Thread(()->{
                try {
                    //获得许可证
                    semaphore.acquire();
                    System.out.println("第"+Thread.currentThread().getName()+"车进来了");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println("第"+Thread.currentThread().getName()+"车走了");
                    //释放许可证
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}