JUC代码演示 适合有一定并发理论基础

本文详细探讨了Java中的线程、守护线程、同步锁(synchronized和Lock接口)、线程间通信、线程安全、公平锁与非公平锁、可重入锁、死锁、并发工具如CountDownLatch、CyclicBarrier、Semaphore、读写锁、阻塞队列、线程池和ForkJoinPool,以及异步编程的CompletableFuture。
摘要由CSDN通过智能技术生成

1. 用户线程与守护线程

public class test1 {
​
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon());   // 用户线程不会随着主线程关闭
            while(true){
​
            }
        },"ydy");
        thread.setDaemon(true);  // 设置为守护线程    守护线程会随着主线程的结束而结束
        thread.start();
        System.out.println("main over");
    }
}

## 2 . Synchronized 同步锁

// 模拟三个窗口同时进行售票
// 上锁以及解锁过程为自动实现
public class test2 {
    static class Ticket {
​
        private Integer sum;
​
        public Ticket(Integer sum) {
            this.sum = sum;
        }
        // 每次卖出一张票
        public synchronized void buy(){
            if(sum > 0) {
                sum --;
                System.out.println(Thread.currentThread().getName() + ":: 售出");
            }
        }
    }
​
    public static void main(String[] args) throws InterruptedException {
        Ticket ticket = new Ticket(50);
​
        // Initialize threads
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0;i < 30;i ++) ticket.buy();
            }
        }, "1").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0;i < 30;i ++) ticket.buy();
            }
        }, "2").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0;i < 30;i ++) ticket.buy();
            }
        }, "3").start();
    }
}

3 . Lock接口

static class Ticket {
    private Integer sum;
    Lock lock = new ReentrantLock();
    public Ticket(Integer sum) {
        this.sum = sum;
    }
    // 每次卖出一张票
    public void buy(){
        lock.lock();
        try{
            if(sum > 0) {
                sum --;
                System.out.println(Thread.currentThread().getName() + ":: 售出");
            }
        }finally {
            lock.unlock();
        }
    }
}

4 . 线程间通信

// 多个线程操作同一个变量
// 使用 synchronized 实现
public class test3 {
    static class Share{
        private int number = 0;
​
        public synchronized void add() throws InterruptedException {
            while(number != 0) this.wait();
            number ++;
            System.out.println(Thread.currentThread().getName() + "::" + "add");
            notifyAll();
        }
        public synchronized void dec() throws InterruptedException {
            while(number != 1) this.wait();
            number --;
            System.out.println(Thread.currentThread().getName() + "::" + "dec");
            notifyAll();
        }
    }
​
    public static void main(String[] args) {
        Share share = new Share();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 1;i <= 10;i ++){
                    try {
                        share.add();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        },"AA").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        share.dec();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }, "BB").start();
    }
}

如果使用的是if 判断的话,可能存在虚假唤醒问题,所以这里使用while循环判断。

// 使用 Lock 接口实现
static class Share{
        private int number = 0;
        private final Lock lock = new ReentrantLock();
        private final Condition condition = lock.newCondition();
        public void add() throws InterruptedException {
            lock.lock();
            try{
                while(number != 0) condition.await();
                number ++;
                System.out.println(Thread.currentThread().getName() + "::" + number);
                condition.signalAll();
            }finally {
                lock.unlock();
            }
        }
        public void dec() throws InterruptedException {
            lock.lock();
            try{
                while(number != 1) condition.await();
                number --;
                System.out.println(Thread.currentThread().getName() + "::" + number);
                condition.signalAll();
            }finally {
                lock.unlock();
            }
​
        }
    }

5 . 线程间定制性通信

// 实现先 打印 A  然后是 BB 之后是 CCC
static class Share{
        private int flag = 1;
        private final Lock lock = new ReentrantLock();
        private final Condition a = lock.newCondition();
        private final Condition b = lock.newCondition();
        private final Condition c = lock.newCondition();
​
        public void printA(){
            lock.lock();
            try {
                while(flag != 1) a.await();
                for (int i = 0; i < 1; i++) {
                    System.out.println("A");
                }
                flag = 2;
                b.signal();  // 通知下一个要操作的线程
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
        public void printB(){
            lock.lock();
            try {
                while(flag != 2) b.await();
                for (int i = 0; i < 2; i++) {
                    System.out.println("B");
                }
                flag = 3;
                c.signal();  // 通知下一个要操作的线程
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
        public void printC(){
            lock.lock();
            try {
                while(flag != 3) c.await();
                for (int i = 0; i < 3; i++) {
                    System.out.println("C");
                }
                flag = 1;
                a.signal();  // 通知下一个要操作的线程
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
​
    }

6 . 集合线程安全

ArrayList

注意:ArrayList是线程不安全的,源码内部没有加锁

多个线程同时存放数据以及获取数据就会发生并发修改异常

解决方案 1 Vector

注意 : 该方法比较古老,现在很少使用

直接用Vector实现类替代ArrayList即可

Vector源码中,其内部方法是加锁的。 Synchronized

解决方案 2 Collections

注意:这个也是古老方法,可能会报错

Collections.synchronizedList(new ArrayList<>());
常用 解决方案 3
List<Object> objects = new CopyOnWriteArrayList<>();

7. HashSet与HashMap的线程安全问题

与ArrayList相同,会出现并发修改访问问题

Set<String> set = new CopyOnWriteArraySet<>();

Map<String, String> hashMap = new ConcurrentHashMap<>();

8.Synchronized 锁的八种情况

9 . 公平锁与非公平锁

公平锁: 阳光普照 但是效率较低

非公平锁: 效率较高,但是可能出现线程饿死问题

Lock lock = new ReentrantLock(true);  // 创建公平锁   不加参数默认是非公平锁
// 源码
/**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
public ReentrantLock() {
    sync = new NonfairSync();
}

/**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

10 . 可重入锁 (递归锁)

synchronized 与 lock 都是可重入锁

简单来说就是在锁内部区域内的代码片段都可以正常访问,不会因为锁而无法访问

public static synchronized void add(){       // 该方法会出现栈溢出异常  
        add();
}

11 . 死锁

所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。

详解链接

死锁面试题(什么是死锁,产生死锁的原因及必要条件)-CSDN博客

12 . Callable接口

FutureTask<Integer> futureTask = new FutureTask<>(() ->{
    return 1024;
});

new Thread(futureTask).start();
System.out.println(futureTask.get());
// 注意 : 当该线程计算完返回值之后,那么下一次调用get方法就不需要等待,直接将之前计算得到的返回值返回。

13. 辅助类

CountDownLatch 减少计数

例如 : 六个打扫教室的同学都离开教室之后,才可以关门。

CountDownLatch countDownLatch = new CountDownLatch(6);
for(int i = 0;i < 6; i++){
	new Thread(() ->{
		System.out.println( Thread.currentThread().getName() + " 号同学离开了");
		countDownLatch.countDown();
	},String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println("关门");
CyclicBarrier 循环栅栏
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,() ->{
            System.out.println("七龙珠收集完毕 ----");
        });

        for (int i = 0; i < 7; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "号 收集到了");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                } catch (BrokenBarrierException e) {
                    throw new RuntimeException(e);
                }
            },String.valueOf(i)).start();
        }
Semaphore 信号灯
Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire(); // 抢占车位
                    System.out.println(Thread.currentThread().getName() + "抢占了车位");

                    TimeUnit.SECONDS.sleep(5);
                    System.out.println(Thread.currentThread().getName() + "-- 离开了车位");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }finally {
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }

14. 读写锁

读锁:共享锁

写锁:独占锁

二者都可能发生死锁现象

// 多线程对于Map集合进行操作
static class MyMap{
        public volatile Map<String, Object> map = new HashMap<>();
        public volatile ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        public void put(String key,Object val){

            try{
                lock.writeLock().lock();
                System.out.println(key + "----开始写数据");
                TimeUnit.SECONDS.sleep(5);
                System.out.println(key + "----::数据写完了");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.writeLock().unlock();
            }
        }
        public void get(String key){
            try {
                lock.readLock().lock();
                System.out.println("----开始读数据" + key);
                TimeUnit.SECONDS.sleep(5);
                System.out.println("----::数据读完了" + key);
            } catch (InterruptedException e) {
            }finally {
                lock.readLock().unlock();
            }
        }
    }

    public static void main(String[] args) {
        MyMap map = new MyMap();
        for(int i = 0;i < 5;i ++){
            final int num = i;
            new Thread(() -> {
                map.put(String.valueOf(num),num);
            },String.valueOf(num)).start();
        }

        for(int i = 0;i < 5;i ++){
            final int num = i;
            new Thread(() -> {
                map.get(String.valueOf(num));
            },String.valueOf(num)).start();
        }
    }
演变

降级

15.阻塞队列 BlockingQueue

16.线程池

在执行一个异步任务或并发任务时,往往是通过直接new Thread()方法来创建新的线程,这样做弊端较多,更好的解决方案是合理地利用线程池,线程池的优势很明显,如下:

降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗; 提高系统响应速度,当有任务到达时,无需等待新线程的创建便能立即执行; 方便线程并发数的管控,线程若是无限制的创建,不仅会额外消耗大量系统资源,更是占用过多资源而阻塞系统或oom等状况,从而 降低系统的稳定性。线程池能有效管控线程,统一分配、调优,提供资源使用率; 更强大的功能,线程池提供了定时、定期以及可控线程数等功能的线程池,使用方便简单。

使用方式:

ExecutorService executorService = Executors.newFixedThreadPool(5);
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
ExecutorService executorService2 = Executors.newCachedThreadPool();
try {
	for (int i = 0; i < 10; i++) {
			executorService2.execute(() -> {
			System.out.println(Thread.currentThread().getName() + ":: 执行");
		});
	}
}finally {
	executorService2.shutdown();  // 线程回收
}

// 七个参数
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
工作流程
自定义线程池
// 自定义线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3,
                10, 60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

17. 分支合并框架

类似于递归 拆分为子问题

static class MyTask extends RecursiveTask<Integer> {
        private Integer b = 10;
        private Integer l,r;

        public MyTask(Integer l,Integer r){
            this.l = l;
            this.r = r;
        }

        @Override
        protected Integer compute() {
            int res = 0;
            if(r - l <= b){
                for(int i = l;i <=r ;i++) res += i;
            }else {
                int mid = (l + r) / 2;
                MyTask t1 = new MyTask(l,mid);
                MyTask t2 = new MyTask(mid + 1,r);
                t1.fork(); t2.fork();

                res = t1.join() + t2.join();
            }
            return res;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyTask task = new MyTask(0,20);

        // 创建分支合并池对象
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(task);
        // 获取分支合并结果
        Integer ans = forkJoinTask.get();
        System.out.println(ans);
        // 关闭池对象
        forkJoinPool.shutdown();
    }

18. 异步回调

CompletableFuture<Void> e1 = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
        });
        e1.get();

        CompletableFuture<Integer> e2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            return 1;
        });
        e2.whenComplete((t,u) -> {  // 返回值t  以及   运行异常u
            System.out.println(t + "::" + u);
        });

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值