Java多线程进阶

参考www.cnblogs.com/hlkawa/tag/JAVA多线程/

一、并发和阻塞队列

1、CountDownLatch类

  实现类似计数器的功能,如在前4个线程执行完后再执行主线程,区别于this.wait/notify使用在类中。

CountDownLatch countDownLatch = new CountDownLatch(2);
countDownLatch.countDown();
countDownLatch.await();  //当前计数为0时才被唤醒

2、CyclicBarrier

  顾名思义:线程到齐后才能跨越这个障碍

  await唤醒方式对比:CountDownLatch    CyclicBarrier

            当前计数减至0    当先等待状态的进程数目是3时,则这3个进程被唤醒。

CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
()->{   cyclicBarrier.await();
  ...do something...
}

3、信号量机制Semaphore

  概念:基于计数,可设置阈值n,m个线程竞争n个信号(m > n),超过阈值时申请的信号会被阻塞。

  功能:用以构建一些对象池、资源池,如数据库连接池;n=1时为互斥锁。

Semaphore sp = new Semaphore(4);
()->{
    int availablePermits = sp.availablePermits();   //当前剩余可获取的信号量数
    sp.acquire();
    sp.release();
}

4、阻塞队列

  概念:生产者消费者问题中,队列容量为10,size在0到10之外时需要this.wait和this.notifyAll(), 而且offer/poll之外需要synchronized。

    顾名思义 阻塞队列在容量外自行阻塞(队列中不得存入null)

  作用:线程安全的 很好地解决了多线程之间通信的问题。

 BlockingQueue<String> queue = new LinkedBlockingQueue<String>(10);
 AtomicInteger atomicInteger = new AtomicInteger();
String data = atomicInteger.incrementAndGet() + "";
boolean flag = queue.offer(data, 2, TimeUnit.SECONDS);

String data = queue.poll(2, TimeUnit.SECONDS);
if(data != null)
    System.out.println(">消费者取出 " + data + "\tSuccess.");
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;


public class BlockingQueueThread {
    private static boolean flag = true;
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new LinkedBlockingQueue<String>(10);
        AtomicInteger atomicInteger = new AtomicInteger();

        for(int i = 0; i < 3; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (flag){
                        String data = atomicInteger.incrementAndGet() + "";
                        try {
                            boolean flag = queue.offer(data, 2, TimeUnit.SECONDS);
                            if(flag)
                                System.out.println("*生产者" + Thread.currentThread().getName() + "存入 " + data + "\tSuccess.");
                            else
                                System.out.println("*生产者" + Thread.currentThread().getName() + "存入 " + data + "\tFailed.");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } // Thread.sleep(100)
                    }
                }
            }).start();
        }

        for(int i = 0; i < 2; i++){
            new Thread(
                    ()->{
                        while (flag){
                            try {
                                String data = queue.poll(2, TimeUnit.SECONDS);
                                if(data != null)
                                    System.out.println(">消费者" + Thread.currentThread().getName() + "取出 " + data + "\tSuccess.");
                                else
                                    System.out.println(">消费者" + Thread.currentThread().getName() + "取出 " + data + "\tFailed.");
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }

                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            } // Thread.sleep(100)
                        }
                    }
            ).start();
        }

        Thread.sleep(100 * 5);
        flag = false;
    }
}
阻塞队列实现 生产者消费者

二、线程池和锁分类

  概念:以线程重用技术避免反复创建与销毁。

  优点:①降低资源损耗; ②提高响应速度; ③提高线程可管理性(方便线程的统一分配、调优、监控,提高系统稳定性)。

  使用范围:短时间内线程大量爆发的场景,高实时响应的任务中。

线程池使用示例pool.submit(()->{}); pool.shutdown();

 Executors工厂类提供4个方法,newSingleThreadExecutor()、newFixedThreadPool(3)、newCachedThreadPool()和newScheduledThreadPool

  即顶层实现的ThreadPoolExecutor类构造方法参数不同。

public static void main(String[] args) {
    ExecutorService threadPool = Executors.newCachedThreadPool();
    for (int i=1;i<= 20;i++) {
        int count = i;
        threadPool.execute(new Runnable() {
             @Override
             public void run() {
                 System.out.println("当前执行任务的线程是  "+ Thread.currentThread().getName() + "    [ i ="+ count + "]");
             }
        });
    }
}

参数

  corePoolSize: 核心线程数、核心池大小 <= cpu_n

  maximumPoolSize: 线程池最大线程数 ∈[cpu_n + 1, 2 * cpu_n] cpu密集型 -> IO密集型。

  keepAliveTime:没有任务执行的线程能存活的时间

  unit: keepAliveTime的时间单位

原理——一个用户任务提交至线程池,处理流程如下:

  ①判断池中核心线程中是否都忙,有空闲则直接执行,否则下一步

  ②判断池中缓存队列是否已满,有空闲则把任务加入队列中等待执行,否则下一步

  ③判断池中所有线程是否都忙,有空闲则创建新工作线程执行,否则交给饱和策略。

 锁的基本分类

  ①悲观锁:每次取数据时都认为其它京城会修改,造成更新丢失。如synchronized, lock锁,mysql的行锁。

  ②公平锁:线程先来先服务FIFO获取锁。synchronized是非公平的,(线程)谁抢到归谁 效率更高。

  ③独占锁:仅允许一个线程持有,其它线程都会等待 如synchronized; 共享锁:多个进程同时持有锁。

    eg:读写锁中"读-读"共享,其它互斥

import java.util.concurrent.locks.ReentrantReadWriteLock;  //读写锁
static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
static Lock r = lock.readLock();
static Lock w = lock.writeLock();
package com.kawa.thread.myStudy;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * TODO
 *
 * @author Administrator
 * @version 1.0
 * @date 2022/3/29 13:29
 */
public class ReadWriteLock {
    static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    static Lock r = lock.readLock();
    static Lock w = lock.writeLock();
    static Map<String, Object> h = new HashMap<String, Object>();

    public static void put(String attr, Object o){
        w.lock();
        h.put(attr, o);
        System.out.println(o + "\tis putted.");
        w.unlock();
    }
    public static Object get(String attr){
        r.lock();
        Object o = h.get(attr);
        System.out.println(o + "\tis getted**.");
        r.unlock();
        return o;
    }
    public static void main(String[] args){
        new Thread(
                ()->{
                    for(int i = 0; i < 5; i++)
                        ReadWriteLock.put(i + "", "hello " + i);
                }
        ).start();
        new Thread(
                ()->{
                    for(int i = 0; i < 5; i++)
                        ReadWriteLock.get(i + "");
                }
        ).start();
    }
}
读写锁-改hashMap为阻塞队列效果更好

  ④重入锁:也叫递归锁,外层函数获得锁之后,内层递归函数一样获取;如synchronized。

  

 

posted @ 2022-03-28 22:18  shines87  阅读(36)  评论(0)    收藏  举报