JUC基础知识篇

2019-06-25 13:11 by 奋斗的奔奔, 阅读, 评论, 收藏, 编辑

java并发实战 — JUC线程高级

1.volatile关键字-内存可见性

内存可见性问题是,当多个线程操作共享数据时,彼此不可见。

volatile关键字:当多个线程操作共享数据时,可以保存内存中的数据是可见的。相较于synchronized是一种较为轻量级的同步策略。

注意:

  1. volatile 不具备互斥性
  2. volatile不能保证变量的原子性

2.原子变量-CAS算法

i++的原子性问题: i++的操作实际上分为三个步骤”读-改-写”。

1 int i = 10;
2 i = i++;//10

1 int temp = i;
2 i = i + 1;
3 i = temp;

原子变量:jdk1.5后java.util.concurrent.atomic包下提供了常用的原子变量:

1.volatile保证内存可见性

2.CAS(Compare-And – Swap)算法保证数据的原子性

 CAS 算法是硬件对于并发操作共享数据的支持

 CAS 包含了三个操作数:

  内存值V

  预估值A

  更新值B

当且仅当 V == A时,V = B,否则,将不做任何操作。

3.ConcurrentHashMap锁分段机制

java5.0 在java.util.concurrent包中提供了多种并发容器类来改进同步容器的性能。

ConcurrentHashMap 同步容器类是java5增加的一个线程安全的哈希表。内部采用“锁分段”机制替代Hashtable的独占锁,进而提高性能。

此包还提供了设计用于多线程上下文中的Collection实现:
ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList、CopyOnWriteArraySet。当期望许多线程访问一个给定collection时,ConcurrentHashMap 通常优于同步的HashMap,ConcurrentSkipListMap通常优于同步的TreeMap。当期望的读数和遍历远远大于列表的更新数时,CopyOnWriteArrayList优于同步的ArrayList。

4.CountDownLatch闭锁

闭锁:一个同步辅助类,在完成某些运算时,只有其他所有线程的运算全部完成,当前运算才继续执行

5.实现Callable接口

**java5.0之后提供了一个新的创建执行线程的方式:Callable接口。
Callable需要依赖FutureTask,FutureTask也可以用作闭锁。
Callable与Runnable的异同点

  1. 两者都是为那些其实例可能被另一个线程执行的类设计的
  2. Runnable不会返回结果,并且无法抛出经过检查的异常
    **

6.Lock同步锁

用于解决多线程安全问题的方式:

synchronized:

  1. 同步代码块
  2. 同步方法

    jdk1.5后

  3. 同步锁Lock

    注意:这是一个显示锁,需要通过lock()方法上锁,必须通过unlock()方法进行释放锁。

    ReentranLock实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性。但相较于synchronized提供了更高的处理锁的灵活性。

    7.Condition控制线程通信

    Cndition接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用Object.wait访问的隐式监视器类似,但提供了更强大的功能。需要特别指出的是,单个Lock可能与多个Condition对象关联。

    在condition对象中,方法分别为await、signal、signalAll。(与我们在操作系统中线程同步章节所学的十分相似。)

    Condition实例实质上被绑定到一个锁上。要为特定Lock实例获得Condition实例,请使用newCondition()方法。

    8.线程八锁

    由于内容太多,只能写个总结。

    线程八锁的关键

    非静态方法的锁默认为实例对象本身,静态方法的锁为对应的类对象本身

    ②某一个时刻内,只能有一个线程持有锁,无论几个方法。

9.线程按序交替

编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示

public class TestABCAlternate {

public static void main(String[] args) {
    AlternateDemo ad = new AlternateDemo();
    
    new Thread(new Runnable() {
        @Override
        public void run() {
            
            for (int i = 1; i <= 20; i++) {
                ad.loopA(i);
            }
            
        }
    }, "A").start();
    
    new Thread(new Runnable() {
        @Override
        public void run() {
            
            for (int i = 1; i <= 20; i++) {
                ad.loopB(i);
            }
            
        }
    }, "B").start();
    
    new Thread(new Runnable() {
        @Override
        public void run() {
            
            for (int i = 1; i <= 20; i++) {
                ad.loopC(i);
                
                System.out.println("-----------------------------------");
            }
            
        }
    }, "C").start();
    }

}

class AlternateDemo{

    private int number = 1; //当前正在执行线程的标记
    
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    
    /**
     * @param totalLoop : 循环第几轮
     */
    public void loopA(int totalLoop){
        lock.lock();
        
        try {
            //1. 判断
            if(number != 1){
                condition1.await();
            }
            
            //2. 打印
            for (int i = 1; i <= 1; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
            }
            
            //3. 唤醒
            number = 2;
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    
    public void loopB(int totalLoop){
        lock.lock();
        
        try {
            //1. 判断
            if(number != 2){
                condition2.await();
            }
            
            //2. 打印
            for (int i = 1; i <= 1; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
            }
            
            //3. 唤醒
            number = 3;
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    
    public void loopC(int totalLoop){
        lock.lock();
        
        try {
            //1. 判断
            if(number != 3){
                condition3.await();
            }
            
            //2. 打印
            for (int i = 1; i <= 1; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
            }
            
            //3. 唤醒
            number = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            }
        }
    }

10.ReadWirteLock读写锁

ReadWriteLock维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有Writer,读取锁可以由多个reader线程同时保持。写入锁是独占的。

ReadWriteLock 读取操作通常不会改变共享资源,但执行写入操作时,必须独占方式来获取锁。

11.线程池

第四种获取线程的方法: 线程池,一个ExecutorService,它使用可能的几个线程池之一执行每个提交的任务,通常使用Executors工厂方法配置。

一、线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。

二、线程池的体系结构:

java.util.concurrent.Executor : 负责线程的使用与调度的根接口

|–ExecutorService 子接口: 线程池的主要接口

|–ThreadPoolExecutor 线程池的实现类

|–ScheduledExecutorService 子接口:负责线程的调度

|–ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService

三、工具类 : Executors

ExecutorService newFixedThreadPool() : 创建固定大小的线程池

ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数

ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程

ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。

12.线程调度

一个ScheduledExecutorService,可安排在给定的延迟后运行或定期地执行命令。

13.ForkJoinPool 分支/合并框架 工作窃取

Fork/Join框架:就是在必要的情况下,将一个大任务,进行拆分成若干个小任务(拆到不可再拆时),再将一个个的小人物运算的结果进行join汇总。

工作窃取 : 当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。

版权声明:本文为liben123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/liben123/p/11082263.html