IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java学习笔记(十一)——JUC并发编程(超详细) -> 正文阅读

[Java知识库]Java学习笔记(十一)——JUC并发编程(超详细)

线程和进程

进程:一个程序的集合,一个进程至少包含一个进程;
Java默认有两个进程,main、GC

线程:一个进程某个功能由线程负责

对于Java而言Thread、Runnable、Callable真的可以开启线程吗?
开不了,通过本地方法native()调用


并发和并行

并发编程:并发、并行,本质是充分利用CPU的资源

并发:多线程操作同一个资源

并行:多个线程同时执行;线程池


线程有几个状态?

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必须要捕获异常


Lock锁(重点)

Synchronized 和 Lock的区别

1.Synchronized 内置的Java关键字,Lock是一个java类
2.Synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁
3.Synchronized 会自动释放锁,Lock必须要手动释放锁!(如果不释放锁会造成死锁)
4.Synchronized 线程1(获得锁,阻塞)、线程3(等待);Lock锁就不一定会等待下去
5.Synchronized 可重入锁,不可以中断的,非公平;Lock可重入锁
,可以判断锁,非公平(可以自己设置)
6.Synchronized 适合锁少量的代码同步问题,Lock适合所大量的同步代码

锁是什么,如何判断锁的是谁


生产者和消费者问题

Synchronized 版

/**
 * 线程之间的通信问题:生产者和消费者问题
 * 线程交替执行 A B操作同一个变量 num=0
 * A num+1
 * B num-1
 */
public class demo01 {
    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 num = 0;

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

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

问题存在,A、B、C、D四个线程是否安全!虚假唤醒(以下是官方文档解释)

解决方法,将if判断改为while循环即可


Lock版

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

/**
 * 线程之间的通信问题:生产者和消费者问题
 * 线程交替执行 A B操作同一个变量 num=0
 * A num+1
 * B num-1
 */
public class demo01 {
    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 num = 0;

    Lock lock=new ReentrantLock();
    Condition con= lock.newCondition();

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

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

Condition精准的通知和唤醒线程

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

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

class Data {
    private Lock lock = new ReentrantLock();
    private Condition con1 = lock.newCondition();
    private Condition con2 = lock.newCondition();
    private Condition con3 = lock.newCondition();
    private int num = 1;

    public void printA() {
        lock.lock();
        try {
            while (num != 1) {
                con1.await();
            }
            System.out.println(Thread.currentThread().getName() + "->" + num);
            num = 2;
            con2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printB() {
        lock.lock();
        try {
            while (num != 2) {
                con2.await();
            }
            System.out.println(Thread.currentThread().getName() + "->" + num);
            num = 3;
            con3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC() {
        lock.lock();
        try {
            while (num != 3) {
                con3.await();
            }
            System.out.println(Thread.currentThread().getName() + "->" + num);
            num = 1;
            con1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

八锁现象

如何判断锁的是谁!永远的知道什么是锁,所得到底是谁!

import java.util.concurrent.TimeUnit;

/**
 * 8锁,就是关于锁的8个问题
 * 1.标准情况下,两个线程先打印发短信还是打电话? 1/发短信 2/打电话
 * 2.sendSms延迟4s,两个线程先打印发短信还是打电话? 1/发短信 2/打电话
 */
public class demo01 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        //锁的存在
        new Thread(() -> {
            phone.sendSms();
        }, "A").start();

        //捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            phone.call();
        }, "B").start();
    }
}

class Phone {

    //Synchronized 锁的对象是方法的调用者
    //两个方法用的是同一个锁,谁先拿到谁执行
    public synchronized void sendSms() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public synchronized void call() {
        System.out.println("打电话");
    }
}
import java.util.concurrent.TimeUnit;

/**
 * 8锁,就是关于锁的8个问题
 * 3.增加了一个普通方法后,发短信还是hello? 先执行普通方法
 * 4.两个对象,两个同步方法,先执行打电话还是发短信? 先打电话
 */
public class demo01 {
    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("发短信");
    }

    public synchronized void call() {
        System.out.println("打电话");
    }

    //这里没有锁,不是同步方法,不受锁的影响
    public void hello() {
        System.out.println("hello");
    }
}
import java.util.concurrent.TimeUnit;

/**
 * 8锁,就是关于锁的8个问题
 * 5.增加两个静态的同步方法,只有一个对象,先打印发短信还是打电话? 先打印发短信
 * 6.两个对象,增加两个静态的同步方法,先打印发短信还是打电话? 先打印发短信
 */
public class demo01 {
    public static void main(String[] args) {
        //两个对象的Class类模板只有一个,static锁的是Class
        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(() -> {
            phone2.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("发短信");
    }

    public static synchronized void call() {
        System.out.println("打电话");
    }
}
import java.util.concurrent.TimeUnit;

/**
 * 8锁,就是关于锁的8个问题
 * 7.1个静态的同步方法,一个普通的同步方法,一个对象,先执行哪一个? 打电话
 * 8.1个静态的同步方法,一个普通的同步方法,两个对象,先执行哪一个? 打电话
 */
public class demo01 {
    public static void main(String[] args) {
        //两个对象的Class类模板只有一个,static锁的是Class
        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("发短信");
    }

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

小结
new this具体的一个Phone
static Class唯一的一个模板


集合类不安全

List不安全

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

//并发下ArrayList不安全

/**
 * 解决方案:
 * 1.List<String> list = new Vector<>();
 * 2.List<String> list = Collections.synchronizedList(new ArrayList<>());
 * 3.List<String> list = new CopyOnWriteArrayList<>();
 */
public class demo01 {
    public static void main(String[] args) {

        //多个线程调用的时候,list,读取的时候是固定的,写入的时候存在覆盖问题 
        List<String> list = new ArrayList<>();
        // CopyOnWrite 写入时复制(COW)计算机程序设计领域的一种优化策略
        // CopyOnWriteArrayList比Vector好在哪里? 
        // Vector存在Synchronized锁会降低效率
        // CopyOnWriteArrayList写入复制,避免覆盖

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

Set不安全

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

/**
 * 解决方案:
 * 1.List<String> list = Collections.synchronizedList(new ArrayList<>());
 * 2.List<String> list = new CopyOnWriteArraySet<>();
 */
public class demo01 {
    public static void main(String[] args) {
        Set<String> set=new HashSet<>();
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }
}

HashSet底层是什么?

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

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

private static final Object PRESENT = new Object(); //不变的值! 

Map不安全

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 解决方案:
 * 1.Map<String,String> map=new ConcurrentHashMap<>();
 */
public class demo01 {
    public static void main(String[] args) {
        //map是这样用的吗? 不是,工作中不用HashMap
        //默认等价于什么? new HashMap()(16,0.75);
        Map<String,String> map=new HashMap<>();

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

Callable
在这里插入图片描述
1.可以有返回值
2.可以抛出异常
3.方法不同,run()/call()

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

public class demo01 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //new Thread(new Runnable()).start();
        //new Thread(new FutureTask<V>()).start();
        //new Thread(new FutureTask<V>(Callable)).start();

        MyThread thread = new MyThread();
        FutureTask fk = new FutureTask(thread);

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

        Integer i = (Integer) fk.get();//这个get方法可能会产生阻塞,把它放在最后
        System.out.println(i);
    }
}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() {
        System.out.println("call()");
        return 1024;
    }
}

常用的辅助类

CountDownLatch

import java.util.concurrent.CountDownLatch;

//减法计数器
public class demo01 {
    public static void main(String[] args) throws InterruptedException {
        //总数是6,必须要执行任务的时候,再使用!
        CountDownLatch cd = new CountDownLatch(6);

        for (int i = 1; i < 6; i++) {
            new Thread(() -> {
                System.out.print(Thread.currentThread().getName() + "Go Out");
                cd.countDown();//数量减一
            }, String.valueOf(i)).start();
        }
        cd.await();//等待计数器归零

        System.out.println("Close");
    }
}

CyclicBarrier

//加法计数器

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

/**
 * 满足设置线程数才可以停止线程
 */
public class Test {
    public static void main(String[] args) {
        CyclicBarrier cy=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 {
                    cy.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

Semaphore

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

//3车六车位
public class demo01 {
    public static void main(String[] args) throws InterruptedException {
        //抢车位
        Semaphore s = new Semaphore(3);

        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                //acquire() 得到
                try {
                    s.acquire();
                    System.out.println(Thread.currentThread().getName() + "抢到车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    s.release();//释放
                }
            }, String.valueOf(i)).start();
        }
    }
}

读写锁

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

/**
 * 独占锁(写锁) 一次只能被一个线程占有
 * 共享锁(读锁) 多个线程可以同时占有
 * ReadWriteLock读写锁
 * 读-读 可以共存
 * 读-写 不能共存
 * 写-写 不能共存
 */
public class demo01 {
    public static void main(String[] args) {
        MyCacheLock mcl = new MyCacheLock();
        //写入
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                mcl.put(temp + "", temp + "");
            }, String.valueOf(i)).start();
        }
        //读取
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                mcl.get(temp + "");
            }, String.valueOf(i)).start();
        }
    }
}

/**
 * 加锁
 */
class MyCacheLock {
    private volatile Map<String, Object> map = new HashMap<>();
    //读写锁
    private ReadWriteLock rwl = new ReentrantReadWriteLock();

    //存,写
    public void put(String key, Object value) {
        rwl.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwl.writeLock().unlock();
        }
    }

    //取,读
    public void get(String key) {
        rwl.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "读取" + key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwl.readLock().unlock();
        }
    }
}

/**
 * 自定义缓存
 * 会产生读写混乱
 */
class MyCache {
    private volatile Map<String, Object> map = new HashMap<>();

    //存,写
    public void put(String key, Object value) {
        System.out.println(Thread.currentThread().getName() + "写入" + key);
        map.put(key, value);
        System.out.println(Thread.currentThread().getName() + "写入OK");
    }

    //取,读
    public void get(String key) {
        System.out.println(Thread.currentThread().getName() + "读取" + key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取OK");
    }
}

阻塞队列

什么情况下我们会使用阻塞队列:多线程并发处理,线程池

package Demo;

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

public class demo01 {
    public static void main(String[] args) throws InterruptedException {
        test1();
    }

    /**
     * 抛出异常
     */
    public static void test1() {
        //队列大小
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));
        //抛出异常 java.lang.IllegalStateException: Queue full
        //System.out.println(blockingQueue.add("d"));
        System.out.println("***********************");
        System.out.println(blockingQueue.element());//获取队首元素
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        //抛出异常 java.util.NoSuchElementException
        System.out.println(blockingQueue.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"));
        System.out.println(blockingQueue.offer("d"));
        System.out.println("************************");
        System.out.println(blockingQueue.peek());//获取队首元素
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        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("************************");
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());//没有这个元素一直阻塞
    }

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

同步队列

package Demo;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
//同步队列和其他的BlockingQueue不一样,SynchronousQueue不存储元素,put了一个元素,必须从里面先take取出来,否则不能再put进去值
public class demo01 {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> blockingQeque = new SynchronousQueue<>();
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " put 1");
                blockingQeque.put("1");
                System.out.println(Thread.currentThread().getName() + " put 2");
                blockingQeque.put("2");
                System.out.println(Thread.currentThread().getName() + " put 3");
                blockingQeque.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T1").start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "->" + blockingQeque.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "->" + blockingQeque.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "->" + blockingQeque.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T2").start();
    }
}

线程池(重点)

线程池:三大方法、七大参数、四种拒绝策略

池化技术
程序运行的本质:占用系统的资源!优化资源的使用->池化技术
池化技术:事先准备好一些资源,有人要用就来我这里拿,用完之后还给我。

线程池的好处:
1.降低资源的消耗
2.提高响应的速度
3.方便管理
线程复用、可以控制最大并发数、管理线程

三大方法

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

//Executors工具类,三大方法
public class demo01 {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();//单个线程
        //ExecutorService executorService = Executors.newFixedThreadPool(5);//创建一个固定的线程池的大小
        //ExecutorService executorService = Executors.newCachedThreadPool();//可伸缩的,遇强则强,遇弱则弱
        try {
            for (int i = 0; i < 100; i++) {
                //使用了线程池之后,使用线程池来创建线程
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + " ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,程序结束,关闭线程池
            executorService.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>());
    }

七大参数

public ThreadPoolExecutor(int corePoolSize, //核心线程池大小
                              int maximumPoolSize, //最大核心线程池大小
                              long keepAliveTime, //超时释放
                              TimeUnit unit, //超时单位
                              BlockingQueue<Runnable> workQueue, //阻塞队列
                              ThreadFactory threadFactory, //线程工厂,创建线程,一般不用更改i
                              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.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

自定义线程池及四种拒绝策略

import java.util.concurrent.*;

class test {
    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                /**
                 * 最大线程数如何定义?
                 *      1.CPU密集型 计算机几核设置为几,可以保持效率最高
                 *          Runtime.getRuntime().availableProcessors();
                 *      2.IO密集型 判断程序中十分消耗IO的线程,一般设置为两倍
                 */
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                /**
                 * 四种拒绝策略
                 *     new ThreadPoolExecutor.AbortPolicy() //超过最大负载,不处理后续载入线程,抛出异常
                 *     new ThreadPoolExecutor.CallerRunsPolicy() //超过最大负载,后续载入线程返回原线程处
                 *     new ThreadPoolExecutor.DiscardPolicy() //超过最大负载,丢弃后续载入线程,不抛出异常
                 *     new ThreadPoolExecutor.DiscardOldestPolicy() //超出最大负载,后续载入线程尝试和最早线程竞争,不抛出异常
                 */
        );
        try {
            for (int i = 0; i < 5; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + " ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

四大函数式接口

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

import java.util.function.Function;
/**
 * Function 函数式接口,有一个输入参数,有一个输出参数
 */
class test {
    public static void main(String[] args) {
        Function<String, String> function = new Function<String, String>() {
            @Override
            public String apply(String str) {
                return str;
            }
        };
        /**
         * lambda表达式简化
         * Function<String, String> function = (str) -> {
         *             return str;
         *         };
         */
        System.out.println(function.apply("test"));
    }
}
import java.util.function.Predicate;
/**
 * Predicate 断定型接口,返回值只能是布尔值
 */
class test {
    public static void main(String[] args) {
        Predicate<String> predicate = new Predicate<String>() {
            @Override
            public boolean test(String str) {
                return str.isEmpty();
            }
        };
        /**
         * lambda表达式简化
         * Predicate<String> predicate = (str) -> {
         *             return str.isEmpty();
         *         };
         */
        System.out.println(predicate.test("test"));
    }
}
import java.util.function.Consumer;
/**
 * Consumer 消费型接口,只有输入没有返回值
 */
class test {
    public static void main(String[] args) {
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String str) {
                System.out.println(str);
            }
        };
        /**
         * Consumer<String> consumer=(str)->{
         *             System.out.println(str);
         *         };
         */
        consumer.accept("test");
    }
}
import java.util.function.Supplier;
/**
 * Supplier 供给型接口,没有参数,只有返回值
 */
class test {
    public static void main(String[] args) {
        Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                return 1024;
            }
        };
        /**
         * Supplier<String> supplier=(str)->{
         *             System.out.println(str);
         *         };
         */
        System.out.println(supplier.get());
    }
}

Stream流式编程

什么是流式计算

大数据:存储+计算
集合、MySQL本质就是存储东西
计算都应该交给流来操作!

import java.util.Arrays;
import java.util.List;

/**
 * 题目要求:一分钟内完成此题,只能用一行代码实现
 * 现在有五个用户!
 * 筛选:
 *      1.ID必须是奇数
 *      2.年龄必须大于21
 *      3.用户名转为大写字母
 *      4.用户名字母倒着排序
 *      5.只输出一个用户
 */
class test {
    public static void main(String[] args) {
        User u1=new User(1,"a",20);
        User u2=new User(2,"b",21);
        User u3=new User(3,"c",22);
        User u4=new User(4,"d",23);
        User u5=new User(5,"e",24);
        //集合就是存储
        List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
        
        //计算交给Stream流
        //lambda表达式、链式编程、函数式接口、Stream流式计算
        list.stream()
                .filter(u->{return u.getId()%2==1;})
                .filter(u->{return u.getAge()>21;})
                .map(u->{return u.getName().toUpperCase();})
                .limit(1)
                .forEach(System.out::println);
    }
}

ForkJoin
ForkJoin在1.7之后,并行执行任务,提高效率(大数据量为前提)

ForkJoin特点:工作窃取

import java.util.concurrent.RecursiveTask;

/**
 * 求和计算任务
 * <p>
 * 如何使用ForkJoin
 * 1.forkjoinpool通过它来执行
 * 2.计算任务forkjoinpool.execute(ForkJoinTask task)
 */
public class ForkJoinDemo extends RecursiveTask<Long> {

    private Long start;
    private Long end;

    //临界值
    private Long temp = 10_0000L;

    ForkJoinDemo(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    public void test() {
        if ((end - start) > temp) {
            //分支合并计算
        }
    }

    @Override
    protected Long compute() {
        if ((end - start) < temp) {
            Long sum = 0L;
            for (Long i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        } else {
            long middle = (start + end) / 2;
            ForkJoinDemo task1 = new ForkJoinDemo(start, middle);
            task1.fork(); //拆分任务将任务压入线程队列
            ForkJoinDemo task2 = new ForkJoinDemo(middle + 1, end);
            task2.fork();
            return task1.join() + task2.join();
        }
    }
}

测试类

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;

class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        test1();
        test2();
        test3();
    }

    public static void test1() {
        Long sum = 0L;
        long start = System.currentTimeMillis();
        for (Long i = 1L; i <= 10_0000_0000; i++) {
            sum += i;
        }
        long end = System.currentTimeMillis();
        System.out.println("sum=" + sum + "时间为:" + (end - start));
    }

    public static void test2() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();

        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoinDemo(0L, 10_0000_0000L);
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);//提交任务
        Long sum = submit.get();
        long end = System.currentTimeMillis();

        System.out.println("sum=" + sum + "时间为:" + (end - start));
    }

    public static void test3() {
        long start = System.currentTimeMillis();
        //Stream并行流
        long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);
        long end = System.currentTimeMillis();
        System.out.println("sum=" + sum + "时间为:" + (end - start));
    }
}

异步回调

Future设计初衷:对将来的某个事件的结果进行建模

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 异步调用:
 * 异步执行
 * 正确回调
 * 失败回调
 */
class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //没有返回值的异步回调
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "runAsync->Void");
        });

        System.out.println("111");

        completableFuture.get();//获取阻塞执行结果

        //有返回值的supplyAsync异步回调
        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "supplyAsync->Integer");
            int i = 10 / 0;
            return 1024;
        });

        System.out.println(completableFuture1.whenComplete((t, u) -> {
            System.out.println("t->" + t); // 正常的返回结果
            System.out.println("u->" + u); // 错误信息
        }).exceptionally((e) -> {
            System.out.println(e.getMessage());
            return 404;
        }).get());
    }
}

单例设计模式:

为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象。
还为了让其他程序可以访问到该类对象,在本类中自定义一个对象。
为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。

  • 代码实现:
    ①将构造函数私有化
    ②在类中创建一个本类对象
    ③提供一个方法可以获取到该对象
//例:饿汉式:载入内存时初始化对象。
class Single {
    private Single() {
    }

    private static Single s = new Single();

    public static Single getInstance() {
        return s;
    }
}

//懒汉式:对象被方法调用时才初始化,也称为对象的延时加载。
class Single {
    private Single() {
    }

    private static Single s = null;

    public static Single getInstance() {
        if (s == null)
            s = new Single();
    }
}

DCL懒汉式

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

//懒汉式单例
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class LazyMan {

    private static boolean code = false;

    private LazyMan() {
        synchronized (LazyMan.class) {
            if (code == false) {
                code = true;
            } else {
                throw new RuntimeException("不要试图使用反射破坏异常");
            }
        }
    }

    private volatile static LazyMan lazyMan;

    //双重检测锁模式 懒汉式单例 DCL懒汉式
    public static LazyMan getInstance() {
        if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    /**
                     * 1.分配内存空间
                     * 2.执行构造方法,初始化对象
                     * 3.把对象指向这个空间
                     */
                    lazyMan = new LazyMan(); //不是一个原子性操作
                }
            }
        }
        return lazyMan;
    }

    //反射
    public static void main(String[] args) throws Exception {

        Field code = LazyMan.class.getDeclaredField("code");
        code.setAccessible(true);

        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan instance = declaredConstructor.newInstance();

        code.set(instance, false);

        LazyMan instance2 = declaredConstructor.newInstance();
    }
}

静态内部类

public class Holder {
    private Holder() {

    }

    public static Holder getInstance() {
        return InnerClass.HOLDER;
    }

    public static class InnerClass {
        private static final Holder HOLDER = new Holder();
    }
}

单例不安全,存在反射

import java.lang.reflect.Constructor;

//enum本身也是一个Class类
public enum EnumSingle {
    INSTANCE;
    public EnumSingle getInstance(){
        return INSTANCE;
    }
}

class Test{
    public static void main(String[] args) throws Exception {
        EnumSingle instance1=EnumSingle.INSTANCE;
        Constructor<EnumSingle> constructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        EnumSingle instance2=constructor.newInstance();

        System.out.println(instance1);
        System.out.println(instance2 );
    }
}

深入理解CAS

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {

    //CAS compareAndSet 比较并交换
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2000);
        atomicInteger.getAndIncrement();//相当于++
        //如果达到期望值那么就更新,否则就不更新,CAS是CPU的并发原语
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());
        atomicInteger.getAndIncrement();

        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());
    }
}

CAS:比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作!如果不是就一直循环!

缺点
1.循环会耗时
2.一次性只能保证一个共享变量的原子性
3.ABA问题

CAS:ABA问题(狸猫换太子)

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {

    //CAS compareAndSet 比较并交换
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //如果达到期望值那么就更新,否则就不更新,CAS是CPU的并发原语
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());

        System.out.println(atomicInteger.compareAndSet(2021, 2020));
        System.out.println(atomicInteger.get());

        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());
    }
}

原子引用

解决ABA问题,引入原子引用!对应的思想:乐观锁

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;

public class CASDemo {

    //CAS compareAndSet 比较并交换
    public static void main(String[] args) {
		//AtomicStampedReference 注意,如果泛型是一个包装类,注意对象的引用问题

		//正常在业务操作,这里面比较的都是一个个对象
        AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1, 1);

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();//获得版本号
            System.out.println("a1->" + stamp);

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicStampedReference.compareAndSet(1, 2, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("a2->" + atomicStampedReference.getStamp());

            System.out.println(atomicStampedReference.compareAndSet(2, 1, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("a3->" + atomicStampedReference.getStamp());

        }, "a").start();
		
		//乐观锁的原理相同
        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();//获得版本号
            System.out.println("b1->" + stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicStampedReference.compareAndSet(1, 2, stamp, stamp + 1));
            System.out.println("b1->" + stamp);

        }, "b").start();
    }
}

Integer使用了对象缓存机制,默认范围是-128~127,推荐使用静态工厂方法valueOf获取对象实例,而不是new,因为valueOF使用缓存,而new一定胡创建新的对象分配新的内存空间


各种锁的理解

公平锁、非公平锁

公平锁:非常公平,不能够插队,必须先来后到!
非公平锁:非常不公平,可以插队(默认都是非公平)

public ReentrantLock() {
        sync = new NonfairSync();
    }
public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

可重入锁(递归锁)
拿到了外面的锁,就可以自动获得里面的锁

//Synchronized版
public class Demo {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(() -> {
            phone.sms();
        }, "A").start();

        new Thread(() -> {
            phone.call();
        }, "B").start();
    }
}

class Phone {
    public synchronized void sms() {
        System.out.println(Thread.currentThread().getName() + " sms");
        call();
    }

    public synchronized void call() {
        System.out.println(Thread.currentThread().getName() + " call");
    }
}
//Lock版
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(() -> {
            phone.sms();
        }, "A").start();

        new Thread(() -> {
            phone.call();
        }, "B").start();
    }
}

class Phone {
    Lock lock = new ReentrantLock();

    public void sms() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " sms");
            call();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void call() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " call");
            call();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

自旋锁

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 自旋锁
 */
class Demo {
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    //加锁
    public void myLock() {
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName() + "-->myLock");

        //自旋锁
        while (!atomicReference.compareAndSet(null, thread)) {

        }
    }

    //解锁
    public void myUnLock() {
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName() + "-->myUnLock");
        atomicReference.compareAndSet(thread, null);
    }
}

class Test {
    public static void main(String[] args) throws InterruptedException {
        Demo d = new Demo();

        new Thread(() -> {
            d.myLock();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                d.myUnLock();
            }
        }, "T1").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(() -> {
            d.myLock();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                d.myUnLock();
            }
        }, "T2").start();
    }
}

死锁排查

死锁的四个前提条件:

互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。

不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。

请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, …, pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, …, n-1),Pn等待的资源被P0占有。

解决死锁
1.使用jps -l 定位进程号
2.使用jstack 进程号找到死锁问题

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-19 11:44:20  更:2021-10-19 11:45:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:01:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码