JUC 并发编程

2 篇文章 0 订阅

多线程进阶==>>JUC 并发编程

1、什么是 JUC

JUC 是 java.util.concurrent 的简写,jdk 中 JUC 相关的包有三个

  • java.util.concurrent 并发相关
  • java.util.concurrent.atomic 原子性
  • java.util.concurrent.locks lock 锁

JUC 意思是 java 并发编程工具包,并发编程的本质就是充分利用 CPU 资源

2、线程和进程

进程:一个程序,程序的集合。

一个进程往往可以包含多个线程,至少包含一个。

java 默认有两个线程,一个 main ,一个 GC

Java 实现多线程:Thread Runnbale Callable

Java 可以开启线程吗不可以

    public synchronized void start() {
        /**
             * This method is not invoked for the main method thread or "system"
             * group threads created/set up by the VM. Any new functionality added
             * to this method in the future may have to also be added to the VM.
             *
             * A zero status value corresponds to state "NEW".
             */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
             * so that it can be added to the group's list of threads
             * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                      it will be passed up the call stack */
            }
        }
    }
	// 本地方法,底层的 C++,java 无法直接操作硬件!
    private native void start0();

并发和并行

并发:多线程操作同一个资源,单核 CPU,模拟多线程,快速交替

并行:多核 CPU,多个线程可以同时执行

public class Test1 {
    public static void main(String[] args) {
        // 获取 CPU 核数
        // CPU 密集型,IO 密集型
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}
线程的状态
public enum State {
    // 新生
    NEW,

    // 运行
    RUNNABLE,

    // 阻塞
    BLOCKED,

    // 等待
    WAITING,

    // 超时等待
    TIMED_WAITING,

    // 终止
    TERMINATED;
}

wait / sleep 的区别

1.来自不同的类
wait - > Object

sleep - > Thread

2.关于锁的释放
wait - > 释放锁

sleep - > 不释放锁

3.使用范围
wait - > 在同步代码块中使用

sleep - > 任何地方

4.是否捕获异常
wait - > 不用捕获异常

sleep - > 必须捕获异常

3、Lock锁

传统 Synchronized

/**
 * 公司中的开发
 * 线程是一个单独的资源类,没有任何附属操作
 * 1.属性 2.方法
 */
public class Demo1 {

    public static void main(String[] args) {
        // 并发,多线程操作操作同一个资源,把资源类丢入线程
        Ticket ticket = new Ticket();

        // @FunctionLInterface 函数式接口,jdk 1.8 lambda 表达式 ()->{}
        new Thread(()->{
            for (int i = 1; i < 30; i ++) {
                ticket.sale();
            }
        }, "A").start();
        new Thread(()->{
            for (int i = 1; i < 30; i ++) {
                ticket.sale();
            }
        }, "B").start();
        new Thread(()->{
            for (int i = 1; i < 30; i ++) {
                ticket.sale();
            }
        }, "C").start();
    }

}

class Ticket {
    private  int number = 20;

    public synchronized void  sale () {
        if (number > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出了" + number-- + "票,剩余" + number);
        }
    }
}

Lock 接口

  • ReentrantLock
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();
}

java 默认非公平锁

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo2 {
    public static void main(String[] args) {
        // 并发,多线程操作操作同一个资源,把资源类丢入线程
        Ticket2 ticket = new Ticket2();
        // @FunctionLInterface 函数式接口,jdk 1.8 lambda 表达式 ()->{}
        new Thread(()->{ for (int i = 1; i < 30; i ++) ticket.sale(); }, "A").start();
        new Thread(()->{ for (int i = 1; i < 30; i ++) ticket.sale(); }, "B").start();
        new Thread(()->{ for (int i = 1; i < 30; i ++) ticket.sale(); }, "C").start();

    }

}

// Lock
// 1. new ReentrantLock();
// 2. Lock.lock();
// 3. lock.unlock();
class Ticket2 {
    private  int number = 20;

    Lock lock = new ReentrantLock();

    public void sale () {
        lock.lock(); // 加锁
        try {
            // 业务代码
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出了" + number-- + "票,剩余" + number);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }
}

Synchronized 和 Lock 的区别

  • Synchronized 内置关键字,Lock 是一个 Java 类
  • Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到锁
  • Synchronized 会自动释放锁,Lock 需要手动释放锁
  • Synchronized 一个线程获得锁阻塞,Lock锁不一定等待下去
  • Synchronized 可重入锁,不可中断,非公平锁;Lock 可重入锁,可以判断锁,可设置是否公平,默认非公平。
  • Synchronized 适合少量代码同步,Lock 适合锁大量同步代码

4、生产者和消费者问题

Synchronized 版

package pc;

/**
 * 线程之间通信问题,生产者和消费者问题,等待通知,等待唤醒
 * 线程交替执行 A B 操作同一个变量,num = 0
 * A num + 1
 * B num - 1
 */
public class Test1 {
    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();
    }
}
// 判断等待 业务 通知
class Data { // 资源类
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        while (number != 0) {
            // 等待
            this.wait();
        }
        number ++;
        System.out.println(Thread.currentThread().getName() + ">>>" + number);
        // 通知其他线程,执行完毕
        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
        while (number == 0) {
            // 等待
            this.wait();
        }
        number --;
        System.out.println(Thread.currentThread().getName() + ">>>" + number);
        // 通知其他线程,执行完毕
        this.notifyAll();
    }

}

JUC 版生产者和消费者

package pc;

import lombok.var;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test2 {
    public static void main(String[] args) {
        Data2 data = new Data2();
        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 Data2 { // 资源类
    private int number = 0;

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
//        condition.await(); // 等待
//        condition.signalAll(); // 唤醒全部

    public void increment() throws InterruptedException {
        try {
            lock.lock();
            while (number != 0) {
                // 等待
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + ">>>" + number);
            // 通知其他线程,执行完毕
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void decrement() throws InterruptedException {
        try {
            lock.lock();
            while (number == 0) {
                // 等待
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + ">>>" + number);
            // 通知其他线程,执行完毕
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

Condition 精准的通知和唤醒线程

package pc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A 执行完调用 B
 * B 执行完调用 C
 */
public class Test3 {
    public static void main(String[] args) {
        Data3 data3 = new Data3();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data3.printA();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data3.printB();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data3.printC();
            }
        }, "C").start();
    }
}

class Data3 {
    private Lock lock = new ReentrantLock();

    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    private int number = 1; //  1A 2B 3C

    public void printA(){
        try {
            lock.lock();
            // 业务代码 判断 - > 执行 - > 通知
            while (number != 1) {
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + " >>> AAA");
            // 唤醒 B
            number = 2;
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printB(){
        try {
            lock.lock();
            while (number != 2) {
                condition2.await();
            }
            // 业务代码 判断 - > 执行 - > 通知
            System.out.println(Thread.currentThread().getName() + " >>> BBB");
            number = 3;
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printC(){
        try {
            lock.lock();
            while (number != 3) {
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName() + " >>> CCC");
            // 业务代码 判断 - > 执行 - > 通知
            number = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

5、8锁现象

深刻理解锁

package lock8;

import java.util.concurrent.TimeUnit;

/**
 * 锁的 8 个问题
 * 1、标准情况下,两个线程先打印 call 还是 sendSms 1、sendSms 2、call
 * 1、sendSms 延时4秒,两个线程先打印 call 还是 sendSms 1、sendSms 2、call
 */
public class Test1 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> {
            phone.sendSms();
        }, "A").start();
        // 捕获
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            phone.call();
        }, "B").start();
    }
}
class Phone{
    // Synchronized 锁定对象,谁先拿到谁执行
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendSms");
    }
    public synchronized void call(){
        System.out.println("call");
    }

}

package lock8;

import java.util.concurrent.TimeUnit;

/**
 * 3、增加了一个普通方法后,先执行 sendSMS 还是 hello
 * 4、两个对象,两个同步方法,先执行 sendSMS 还是 hello
 */
public class Test2 {
    public static void main(String[] args) {
        Phone2 phone1 = new Phone2();
        Phone2 phone2 = new Phone2();
        new Thread(() -> {
            phone1.sendSms();
        }, "A").start();
        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            phone2.call();
        }, "B").start();
    }
}
class Phone2 {
    // Synchronized 锁定对象,谁先拿到谁执行
    public synchronized void sendSms() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendSms");
    }

    public synchronized void call() {
        System.out.println("call");
    }
    public void hello() {
        System.out.println("hello");
    }
}
package lock8;

import java.util.concurrent.TimeUnit;

/**
 * 5、增加两个静态同步方法,只有一个对象,先 sendSMS 还是先 call
 * 6、两个对象,增加两个惊天同步方法
 */
public class Test3 {
    public static void main(String[] args) {
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();
        new Thread(() -> {
            phone1.sendSms();
        }, "A").start();
        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            phone1.call();
        }, "B").start();
    }
}
class Phone3 {
    // Synchronized 锁定对象,谁先拿到谁执行
    // static 静态方法
    // 类加载就有了,锁的是 class
    public static synchronized void sendSms() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendSms");
    }

    public static synchronized void call() {
        System.out.println("call");
    }
    public void hello() {
        System.out.println("hello");
    }
}

package lock8;

import java.util.concurrent.TimeUnit;

/**
 * 7、1个静态的同步方法,一个普通同步方法,一个对象
 * 8、1个静态同步方法,1个普通同步方法,两个对象
 */
public class Test4 {
    public static void main(String[] args) {
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        new Thread(() -> {
            phone1.sendSms();
        }, "A").start();
        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            phone2.call();
        }, "B").start();
    }
}
class Phone4 {
    // 静态同步方法 锁的是 Class 类
    public static synchronized void sendSms() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendSms");
    }

    // 普通同步方法 锁的调用者
    public synchronized void call() {
        System.out.println("call");
    }
    public void hello() {
        System.out.println("hello");
    }
}

小结

new this 锁的是对象是方法的调用者,也就是 new 出来的对象,调用这个方法

static Class 的唯一一个模板

锁的对象相同,谁先获得锁先执行,锁的对象不同,分开执行不冲突

6、集合类不安全

List 类不安全

package unsafe;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 *  ConcurrentModificationException 并发修改异常
 */
public class ListTest {
    public static void main(String[] args) {
        // 并发下 ArrayList 不安全

        /**
         * ArrayList<String> list = new ArrayList<>();
         * List<String> list = new Vector<>();
         * List<String> list = Collections.synchronizedList(new ArrayList<>());
          */

        // CopyOnWrite 写入时复制
        //  多个线程调用的时候,list,读取的时候,固定的,写入(覆盖)
        // 写入的时候避免覆盖,造成数据分离
        
        // CopyOnWriteArrayList 比 Vector 好在在哪里?
        // CopyOnWriteArrayList 使用的 lock 锁,没有使用 Synchronized
        List<String> list = new CopyOnWriteArrayList<>();

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

    }
}

Set 不安全

package unsafe;

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

public class SetTest {
    public static void main(String[] args) {
        // 1、Set<String> set = new HashSet<>();
        // 2、Set<String> set = Collections.synchronizedSet(new HashSet<String>());
        Set<String> set = new CopyOnWriteArraySet<String>();

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

        }
    }
}

HashSet 的底层实现

public HashSet() {
    map = new HashMap<>();
}

// add set 是无序的,map 的 key 无法重复
public boolean add(Ee) {
    return map.put(e, PRESENT) == null;
}

map 不安全

package unsafe;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class MapTest {
    public static void main(String[] args) {
        // map 是这样用吗?
        // 默认等价于什么 new HashMap<>();
        // 负载因子,初始化容量
        // Map<String, String> map = new HashMap<>();
        // Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());
        Map<String, String> map = new ConcurrentHashMap<>();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,3));
                System.out.println(map);
            }, String.valueOf(i)).start();

        }
    }
}

7、Callable

  • 可以有返回值
  • 可以抛出异常
  • 方法不同,call()
package callable;

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

public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // new Thread(new MyThread()).start();
        // new Thread(new FutureTask<v>()).start();
        // new Thread(new FutureTask<v>(Callable)).start();
        MyThread myThread = new MyThread();
        FutureTask futureTask = new FutureTask<>(myThread);
        // 适配类
        new Thread(futureTask, "A").start();

        String string = (String) futureTask.get(); // get 可能等待,会阻塞
        System.out.println(string);
    }
}
class MyThread implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println("call()");
        return "123456";
    }
}

8、常用辅助类

  • CountDownLatch 减法计数器
package add;

import java.util.concurrent.CountDownLatch;

// 计数器
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        // 总数是 6,必须要执行任务时使用
        CountDownLatch countDownLatch = new CountDownLatch(5);

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "Go out");
                countDownLatch.countDown(); // 数量 -1
            }, String.valueOf(i)).start();
        }
        countDownLatch.await(); // 等待计数器归零再向下执行
        System.out.println("close the door");
    }

}

countDownLatch.countDown(); // 数量 -1

countDownLatch.await(); // 等待计数器归零再向下执行

  • CyclicBarrier 加法计数器

指定个数线程执行完再执行操作

package add;

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

public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,() -> {
            System.out.println("成功");
        });
        for (int i = 0; i < 7; i++) {
            final int temp = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + temp);
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}

  • Semaphore 信号量

同一时间只能有指定数量得到线程

package add;

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

public class SemaphoreTest {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(6);
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                // acquire 得到
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "抢到");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "离开");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // release 释放
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}

semaphore.acquire();获得,满了将等待

semaphore.release();释放,当前信号量释放 +1,唤醒等待的线程

作用:多个共享资源互斥使用,并发限流。

9、读写锁

ReadWriteLock

package rw;

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

/**
 * 独占锁(写锁),一次只能一个线程占有
 * 共享锁(读锁),可以多个线程占有
 * ReadWriteLock
 * 读 - 读
 * 读 - 写
 * 写 - 写
 */
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(() -> {
                    myCache.put(temp+"", temp);
            }, String.valueOf(i)).start();
        }
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.get(temp+"");
            }, String.valueOf(i)).start();
        }
    }
}

/**
 * 自定义缓存
 */
class MyCache {
    private volatile Map<String, Object> map = new HashMap<>();
    // 读写锁,更加细粒度的控制
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    // 存,写入时同时被一个线程执行
    public void put(String key, Object value) {
        try {
            readWriteLock.writeLock().lock();
            System.out.println(Thread.currentThread().getName() + "写入key" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入完成" + key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    // 取,读
    public void get(String key) {
        try {
            readWriteLock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + "获取key" + key);
            map.get(key);
            System.out.println(Thread.currentThread().getName() + "获取完成" + key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}

10、阻塞队列

Queue

Dqueue:双端队列

BlockingQueue:阻塞队列

AbstractQueue:非阻塞队列

四组 API

方式抛出异常不会抛出异常阻塞等待超时等待
添加addofferputoffer(e, timeout, unit)
移除removepooltakepoll(timeout, unit)
检测队首元素elementpeek

抛出异常

package blockqueue;

import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

public class BlcokQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        // Collection
        // List
        // Set
        // BlockingQueue
        // test1();
        // test2();
        // test3();
        test4();
    }

    /**
     * 抛出异常
     */
    public static void test1() {
        // 参数队列大小
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(arrayBlockingQueue.add("a"));
        System.out.println(arrayBlockingQueue.add("b"));
        System.out.println(arrayBlockingQueue.add("c"));

        // 检测队首元素
        System.out.println(arrayBlockingQueue.element());
        // 队列满抛出异常
        // Exception in thread "main" java.lang.IllegalStateException: Queue full
        // System.out.println(arrayBlockingQueue.add("d"));
        System.out.println(arrayBlockingQueue.remove());
        System.out.println(arrayBlockingQueue.remove());
        System.out.println(arrayBlockingQueue.remove());
        // 没有元素抛出异常
        // Exception in thread "main" java.util.NoSuchElementException
        System.out.println(arrayBlockingQueue.remove());
    }

    /**
     * 有返回值,不抛出异常
     */
    public static void test2() {

        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        // 超出队列长度,返回 false 不抛出异常
        // System.out.println(blockingQueue.offer("d"));

        // 检测队首元素
        System.out.println(blockingQueue.peek());

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        // 返回 null,没有异常
        System.out.println(blockingQueue.poll());

    }

    /**
     * 等待,阻塞(一直阻塞)
     */
    public static void test3() throws InterruptedException {
        ArrayBlockingQueue blockingQUeue = new ArrayBlockingQueue<>(3);
        // 一直阻塞
        blockingQUeue.put("a");
        blockingQUeue.put("b");
        blockingQUeue.put("c");
        // 超过队列长度一直阻塞
        // blockingQUeue.put("d");

        System.out.println(blockingQUeue.take());
        System.out.println(blockingQUeue.take());
        System.out.println(blockingQUeue.take());
        // 没有元素会一直阻塞
        System.out.println(blockingQUeue.take());
    }

    /**
     * 等待,阻塞,超时退出
     */
    public static void test4() throws InterruptedException {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        // 超时等待两秒就退出
        System.out.println(blockingQueue.offer("d", 2, TimeUnit.SECONDS));
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS));
    }
}

SynchronousQueue 同步队列

没有容量,put 元素之后需要 take 取出来。

package blockqueue;

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * 同步队列
 * SynchrnousQueue 不存储元素
 * put 了一个元素,必选先从里面取出来,否则不能再put进去东西
 */
@SuppressWarnings("all")
public class SynchronizedDemo {

    public static void main(String[] args) {
        SynchronousQueue<String> synchronousQueue = new SynchronousQueue<>();
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "put1");
                synchronousQueue.put("1");
                System.out.println(Thread.currentThread().getName() + "put2");
                synchronousQueue.put("2");
                System.out.println(Thread.currentThread().getName() + "put3");
                synchronousQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1").start();
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName());
                synchronousQueue.take();
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName());
                synchronousQueue.take();
                System.out.println(Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(2);
                synchronousQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2").start();


    }
}

11、线程池

池化技术

程序的运行,会消耗系统资源,我们需要优化资源的使用,使用了池化技术

线程池,连接池,内存池,常量池,内存池等。

线程池的好处

  1. 降低资源消耗,创建和销毁线程非常消耗资源
  2. 提高响应速度
  3. 方便对线程的管理
方法
  • Executors.newSingleThreadExecutor(); 单线程池
  • Executors.newFixedThreadExecutor(); 定长线程池
  • Executors.newCachedThreadExecutor(); 缓存线程池,可变长度线程池
package pool;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Executors 工具类三大方法
 * 使用了线程池后,使用线程池创建线程
 */
public class Demo1 {
    public static void main(String[] args) {
        // 单个线程
//        ExecutorService executor = Executors.newSingleThreadExecutor();
        // 固定线程池
//        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 可变长度线程池
        ExecutorService executor = Executors.newCachedThreadPool();

        try {
            for (int i = 0; i < 100; i++) {
                // 使用线程池创建线程
                executor.execute(() -> {
                    System.out.println(Thread.currentThread().getName());
                });

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 线程池使用完毕关闭线程池
            executor.shutdown();
        }


    }
}

参数

源码:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}


public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

// 本质:ThreadPoolExecutor ()

    public ThreadPoolExecutor(int corePoolSize, // 核心线程数
                              int maximumPoolSize, // 最大线程池大小
                              long keepAliveTime, // 超时时间
                              TimeUnit unit, // 超时单位
                              BlockingQueue<Runnable> workQueue, // 阻塞队列
                              ThreadFactory threadFactory, // 线程工厂
                              RejectedExecutionHandler handler) { // 拒绝策略
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
        null :
    AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

四种拒绝策略
在这里插入图片描述

AbortPolicy:默认拒绝策略,队列满了抛出异常

CallerRunsPolicy:队列满了不抛出异常,主线程进行处理

DiscardPolicy:不会抛出异常,放弃任务执行

DiscardOldesPolicy:队列满了,不抛出异常,尝试和最早的进行竞争

线程池大小如何设置

1、CPU 密集型,几核就是几

2、IO 密集型,> 程序中非常耗费 IO 的线程

12、四大函数式接口

函数式接口:只有一个方法的接口

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

function 函数式接口

package function;

import java.util.function.Function;

/**
 * Function 函数型接口,有一个输入参数,一个输出参数
 * 函数型接口可以用 lambda 表达式简化
 */
public class Demo1 {
    public static void main(String[] args) {
        Function function = new Function<String, String>() {
            @Override
            public String apply(String o) {
                return null;
            }
        };
        Function function1 = (str) -> {return str};

        System.out.println(function.apply("asdf"));
    }
}

断定型接口

package function;

import java.util.function.Predicate;

/**
 * 断定型接口
 */
public class Demo2 {
    public static void main(String[] args) {
        Predicate<String> predicate = new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.isEmpty();
            }
        };
        Predicate<String> predicate1 = (str) -> {return str.isEmpty();};
        System.out.println(predicate1.test(""));
    }
}

Consumer 消费型接口

package function;

import java.util.function.Consumer;

/**
 * Consumer 消费型接口,只有输入,没有返回值
 */
public class Demo3 {
    public static void main(String[] args) {
        Consumer<String> stringConsumer = new Consumer<String>() {
            @Override
            public void accept(String o) {
                System.out.println(o);
            }
        };
        Consumer<String> consumer = (str) -> {
            System.out.println(str);
        };
        stringConsumer.accept("ooooo");
    }
}

Supplier 供给型接口

package function;

import java.util.function.Supplier;

/**
 * 供给型接口,没有参数,有返回值
 */
public class Demo4 {
    public static void main(String[] args) {
        Supplier<String> stringSupplier = new Supplier<String>() {
            @Override
            public String get() {
                return "方法调用了";
            }
        };
        Supplier supplier = () -> {return "asdf";};
        System.out.println(supplier.get());
    }
}

13、Stream 流式计算

14、ForkJoin

ForkJoin 特点:工作窃取。ForkJoin 中维护的都是双端队列

15、异步回调

16、JMM

Volatitle 是 Java 虚拟机提供的轻量级的同步机制

  1. 保证可见性
  2. 不保证原子性
  3. 禁止指令重排

JMM:java 内存模型

JMM 一些同步的约定

  1. 线程解锁前,必须把共享变量立刻刷回主存
  2. 线程加锁前,必须读取主存中的最新值到工作内存中
  3. 加锁和解锁是同一把锁

线程:工作内存、主内存

内存交互的八种操作

lock 锁定 => unlock 解锁 => read 读取 => load 载入 => use 使用 => assign 赋值 => store 存储 => write 写入

17、Volatitle

  • 保证可见性
public class JMMDemo {
    // 使用 volatile 保证可见性
    private volatile static int num = 0;
    public static void main(String[] args) {
		// 线程 1
        new Thread(() -> {
            while (num == 0) {
                
            }
        }).start();
        try{
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        num = 1;
    }
}
  • 不保证原子性
public class VDemo2 {
    // volatile 不保证原子性
    private volatile static int num = 0;
    public void add(){
        num ++;
    }
    public static void main(String[] args) {
		// 理论上应该为 20000
        for (int i = 1; i <= 20; i++) {
            new Thread(() -> {
                for(int j = 0; j < 1000; j++) {
                    add();
                }
            }).start();
        }
        while (Thread.activeCount() > 2) { // main GC
            Thread.yield();
        }
    }
}

如果不使用 lock 和 Synchronized 怎么保证原子性

使用原子类进行操作

public class VDemo2 {
    // 原子类的 Integer
    private static AtomicInteger num = new AtomicInteger();
    public void add(){
	    // AtomicInteger +1 方法,CAS
        num.getAndIncrement();
    }
    public static void main(String[] args) {
		// 理论上应该为 20000
        for (int i = 1; i <= 20; i++) {
            new Thread(() -> {
                for(int j = 0; j < 1000; j++) {
                    add();
                }
            }).start();
        }
        while (Thread.activeCount() > 2) { // main GC
            Thread.yield();
        }
    }
}

这些类底层与操作系统挂钩,在内存中修改值,unsafe 类是个特殊的存在

指令重排

源代码 => 编译器优化重排 => 指令并行可能进行重排 => 内存系统也会进行重排 => 执行

处理器作指令重排时,考虑:数据之间的依赖性问题

volatile 可以禁止指令重排:内存屏障。CPU指令。作用:

  • 保证特定的执行顺序
  • 可以保证某些变量的内存可见性(利用这些特性可以保证 volatile 的可见性)

Volatile 在单例模式中使用的多

18、单例模式

饿汉式

// 饿汉式单例
public class Hungry {
    // 可能会浪费空间
    private byte[] data = new byte[1024*1024];
    private Hungry(){};
    private final static Hungry HUNGRY = new Hungry();
    public static Hungry getInstance(){
        return HUNGRY;
    }
}

懒汉式

public class lazyMan {
    private LazyMan(){};
    private volatile static LazyMan lazyMan;
    
    // 双重检测锁模式,DCL 懒汉式
    public static LazyMan getInstance(){
        if (lazyMa == null ) {
            synchronized (LazyMan.class){
                if(LazyMan == null) {
                    // 1、分配内存空间
                    // 2、执行构造方法,初始化对象
                    // 3、把对象指向内存空间
            		lazyMan = new LazyMan(); // 不是原子性操作
        		}    
            }
        }
        return lazyMan;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一起来搬砖呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值