(大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程(一)⭐学妹已收藏

简介: (大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程(一)⭐学妹已收藏

❤️‍  大家好,我是java厂长,今天带你们体验一把多线程高并发的面试高频!❤️‍

JUC学习

文章目录

1、什么是JUC

image.png

源码+官方文档

JUC是 java util concurrent

面试高频问JUC~!

image.png

java.util 是Java的一个工具包

业务:普通的线程代码 Thread

Runnable: 没有返回值、效率相比于Callable 相对较低!

image.png

2、线程和进程

进程:一个程序,允许一个java程序会进程里面会出现一个java.exe;数据+代码+pcb

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

Java默认有几个线程?2个线程! main线程、GC线程

线程:开了一个进程qq,聊天打字,消息提示(线程负责的)

对于Java而言:Thread、Runable、Callable进行开启线程的。

JAVA真的可以开启线程吗? 开不了的!

原因Java没有权限去开启线程、操作硬件的,这是一个native的一个本地方法,它调用的底层的C++代码。

并发、并行

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

  • CPU 只有一核,模拟出来多条线程,那么我们就可以使用CPU快速交替,来模拟多线程。

并行: 多个人并排行走。

  • CPU多核,多个线程可以同时执行。
public class Test {
    public static void main(String[] args) {
        //获取cpu的核数
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

并发编程的本质:充分利用CPU的资源!

线程的6个状态

public enum State {
      //创建
        NEW,
      //运行
        RUNNABLE,
      //阻塞
        BLOCKED,
      //等待
        WAITING,
      //超时等待
        TIMED_WAITING,
      //终止
        TERMINATED;
    }

面试题:谈一谈wait和sleep区别?

区别 wait sleep
操作的类 Object Thread
锁的释放 会释放锁 抱着锁睡觉
范围 同步代码块中 任何地方
异常捕获 不需要捕获异常 需要捕获异常

3、Lock锁(重点)

synchronized锁问题

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: TicketTest
 * @Author: 张晟睿
 * @Date: 2021/9/5 14:01
 * @Version: 1.0
 */
//资源类 属性 + 方法 oop
class Ticket{
    private int num = 50;
    //卖票方式  synchronized 本质:队列 锁
    public synchronized void sale(){
        if(num > 0){
            System.out.println(Thread.currentThread().getName()+ " 卖出了第"+ num +" 张票,剩余:"+ --num +" 张票");
        }
    }
}
public class TicketTest {
    public static void main(String[] args) {
        //多线陈操作
        //并发:多个线程操作同一个资源ticket
        Ticket ticket = new Ticket();
        //@FunctionalInterface 函数式接口 jdk1.8之后 lambda表达式
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"C").start();
    }
}

Lock接口

image.png

image.png

image.png

公平锁: 公平,必须先来后到~;

非公平锁: 不公平,可以插队;(默认为非公平锁)

使用Lock进行操作

package com.zmz.day01;/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: TicketTest2
 * @Author: 张晟睿
 * @Date: 2021/9/5 16:15
 * @Version: 1.0
 */
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 *@ClassName TicketTest2
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
class Ticket2{
    /*
    * 加锁三步
    * 1.实例化lock对象
    * 2.lock加锁
    * 3.unlock解锁
    * */
    Lock l = new ReentrantLock();
    private int num = 50;
    //卖票方式  synchronized 本质:队列 锁
    public  void sale(){
        //加锁
        l.lock();
        try {
            //业务代码
            if(num > 0){
                System.out.println(Thread.currentThread().getName()+ " 卖出了第"+ num +" 张票,剩余:"+ --num +" 张票");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //解锁
            l.unlock();
        }
    }
}
public class TicketTest2 {
    public static void main(String[] args) {
        //多线陈操作
        //并发:多个线程操作同一个资源ticket
        Ticket ticket = new Ticket();
        //@FunctionalInterface 函数式接口 jdk1.8之后 lambda表达式
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"C").start();
    }
}
区别 synchronized lock
名称 属于关键字 属于对象
状态 不可以获取锁的状态 可以获取锁的状态
锁的管理 自动释放锁 需要手动加锁以及释放锁
线程 自己抱着锁 等待
可重入锁,不可以中断的,非公平的 可重入的,可以判断锁,可以自己设置公平锁和非公平锁
代码同步 适合少量的代码同步 适合大量的代码同步

4、生产者消费者问题

synchronized版

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: TicketTest3
 * @Author: 张晟睿
 * @Date: 2021/9/5 16:35
 * @Version: 1.0
 */
/**
 *@ClassName TicketTest3
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
public class TicketTest3 {
    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;
    //      +1操作
    public synchronized void increment() throws InterruptedException {
        if(number != 0 ){
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();
    }
    //      -1操作
    public synchronized void decrement() throws InterruptedException{
        if (number == 0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();
    }
}

问题存在,A线程B线程,现在如果我有四个线程A B C D!该怎么去解决问题

image.png

if判断改为While判断就可以解决虚假唤醒的问题。

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: TicketTest3
 * @Author: 张晟睿
 * @Date: 2021/9/5 16:35
 * @Version: 1.0
 */
/**
 *@ClassName TicketTest3
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
//线程之间的通讯问题:生产者和消费者的问题!  等待唤醒,通知唤醒
//线程交替执行 A   B操作同一个资源
public class TicketTest3 {
    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();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } 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 Data{
    private int number = 0;
    //      +1操作
    public synchronized void increment() throws InterruptedException {
        while(number != 0 ){
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();
    }
    //      -1操作
    public synchronized void decrement() throws InterruptedException{
        while (number == 0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();
    }
}

JUC版本的解决A B C D多线程的问题

image.png

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: JucTest1
 * @Author: 张晟睿
 * @Date: 2021/9/5 19:34
 * @Version: 1.0
 */
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 *@ClassName JucTest1
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
public class JucTest1 {
    public static void main(String[] args) {
        Data2 data = new Data2();
        new Thread(()->{for(int i=0;i<10;i++) {
            data.increment();
        }
        },"A").start();
        new Thread(()->{for(int i=0;i<10;i++) {
            data.decrement();
        }},"B").start();
        new Thread(()->{for(int i=0;i<10;i++) {
            data.increment();
        }
        },"C").start();
        new Thread(()->{for(int i=0;i<10;i++) {
            data.decrement();
        }
        },"D").start();
    }
}
class Data2{
    private int number = 0;
    //lock锁
    Lock l = new ReentrantLock();
    Condition condition = l.newCondition();
    public void increment() {
        l.lock();
        try {
            //业务
            while (number!=0){
                //等待操作
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            //通知其他线程 我+1完毕了
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }
    public void decrement()  {
        l.lock();
        try {
            //业务
            while (number==0){
                //等待操作
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            //通知其他线程 我-1完毕了
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }
}

Condition的优势:精准通知、唤醒的线程

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: JucTest2
 * @Author: 张晟睿
 * @Date: 2021/9/5 19:52
 * @Version: 1.0
 */
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 *@ClassName JucTest2
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
public class JucTest2 {
    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 l = new ReentrantLock();
    Condition condition1 = l.newCondition();
    Condition condition2 = l.newCondition();
    Condition condition3 = l.newCondition();
    private int flag = 1;
    public void printA(){
        l.lock();
        //判断 -> 执行 -> 通知
        try {
            while(flag != 1){
                //等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "->A" );
            flag = 2;
            //唤醒指定线程
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }
    public void printB(){
        l.lock();
        //判断 -> 执行 -> 通知
        try {
            while(flag != 2){
                //等待
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName() + "->BB" );
            flag = 3;
            //唤醒指定线程
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }
    public void printC(){
        l.lock();
        //判断 -> 执行 -> 通知
        try {
            while(flag != 3){
                //等待
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName() + "->CCC" );
            flag = 1;
            //唤醒指定线程
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }
}

5、8锁现象

1-2锁

package com.zmz.lock8;/**
 * @ProjectName: Juc
 * @Package: com.zmz.lock8
 * @ClassName: Test1
 * @Author: 张晟睿
 * @Date: 2021/9/5 21:18
 * @Version: 1.0
 */
import java.util.concurrent.TimeUnit;
/**
 *@ClassName Test1
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
/*
* 8锁,就是关于锁的8个问题
* 1、标准情况下,两个线程先打印 发短信还是打电话?  发短信
* 2、sendSms方法延迟4s,两个线程先打印 发短信还是打电话?  发短信
* */
public class Test1 {
    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锁的对象是方法的调用者!
    //两个方法用的都是phone对象的锁!
    //谁先拿到谁执行!
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}

image.png

3-4锁

package com.zmz.lock8;/**
 * @ProjectName: Juc
 * @Package: com.zmz.lock8
 * @ClassName: Test2
 * @Author: 张晟睿
 * @Date: 2021/9/5 21:26
 * @Version: 1.0
 */
import java.util.concurrent.TimeUnit;
/**
 *@ClassName Test2
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
//3、增加一个普通方法后! 发短信还是Hello,发短信       hello
//4、两个对象,两个同步方法,发短信还是打电话      打电话
public class Test2 {
    public static void main(String[] args) {
        //两个对象,两把锁
        Phone2 phone = new Phone2();
        Phone2 phone2 = new Phone2();
        //锁存在
        new Thread(()->{
            phone.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("打电话");
    }
    //这里没有锁!bubu不是同步方法,不受锁的影响
  public void hello(){
        System.out.println("hello");
    }
}

image.png

image.png

5-6锁

package com.zmz.lock8;/**
 * @ProjectName: Juc
 * @Package: com.zmz.lock8
 * @ClassName: Test3
 * @Author: 张晟睿
 * @Date: 2021/9/6 12:35
 * @Version: 1.0
 */
import java.util.concurrent.TimeUnit;
/**
 *@ClassName Test3
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/6
 **/
/*
* 5、增加两个静态同步方法,只有一个对象,先打印发短信还是打电话?  发短信
* 6、两个对象!增加两个静态同步方法,只有一个对象,先打印发短信还是打电话  发短信
* */
public class Test3 {
    public static void main(String[] args) {
        //两个对象,两个调用者,两把锁!
        //两个对象的class类模板只有一个,static,锁的是Class
        Phone3 phone = new Phone3();
        Phone3 phone2 = new Phone3();
        //锁存在
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}
//Phone3唯一的一个Class对象
class Phone3{
    //synchronized锁的对象是方法的调用者!
    //static 静态方法
    //类一加载就有了!Class 模板 锁的是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("打电话");
    }
}

image.png

7-8锁

package com.zmz.lock8;/**
 * @ProjectName: Juc
 * @Package: com.zmz.lock8
 * @ClassName: Test4
 * @Author: 张晟睿
 * @Date: 2021/9/6 13:07
 * @Version: 1.0
 */
import java.util.concurrent.TimeUnit;
/**
 *@ClassName Test4
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/6
 **/
/*
* 1个静态同步方法,1个同步方法,1个对象 先打印发短信还是打电话?   打电话
* 1个静态同步方法,1个同步方法,2个对象 先打印发短信还是打电话?   发短信
* */
public class Test4 {
    public static void main(String[] args) {
        //两个对象,两个调用者,两把锁!
        //两个对象的class类模板只有一个,static,锁的是Class
        Phone4 phone = new Phone4();
        //锁存在
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        },"B").start();
    }
}
//Phone4唯一的一个Class对象
class Phone4{
    //synchronized锁的对象是方法的调用者!
    //锁的是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("打电话");
    }
}

image.png

6、集合不安全

1、ArrayList集合不安全

package com;/**
 * @ProjectName: Juc
 * @Package: com
 * @ClassName: unsafe
 * @Author: 张晟睿
 * @Date: 2021/9/6 19:37
 * @Version: 1.0
 */
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
 *@ClassName unsafe
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/6
 **/
public class unsafe {
    public static void main(String[] args) {
        //高并发下的ArrayList真的安全么?
        /**
         * 解决方法
         * 1、List<String> list = new Vector<String>();
         * 2、List<String> list = Collections.synchronizedList(new ArrayList<>());
         * 3、List<String> list = new CopyOnWriteArrayList<>();
         * */
        List<String> list = new CopyOnWriteArrayList<>();
        //启动10个多线程
        for (int i = 1; i < 10; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}

CopyOnWriteArrayList源码分析

image.png

2、Set不安全

package com.zmz.unsafe;/**
 * @ProjectName: Juc
 * @Package: com.zmz.unsafe
 * @ClassName: SetSafe
 * @Author: 张晟睿
 * @Date: 2021/9/6 21:20
 * @Version: 1.0
 */
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
/**
 *@ClassName SetSafe
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/6
 **/
public class SetSafe {
    public static void main(String[] args) {
        //Set<String> set = new HashSet<>();
        //Set<String> set = Collections.synchronizedSet(new HashSet<>());
        Set<String> set = new CopyOnWriteArraySet<>();
        for (int i = 1; i < 60; 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<>();
    }
  //HashSet本质就是Map集合
  public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
private static final Object PRESENT = new Object();//不变的值

3、HashMap不安全

package com.zmz.unsafe;/**
 * @ProjectName: Juc
 * @Package: com.zmz.unsafe
 * @ClassName: MapSafe
 * @Author: 张晟睿
 * @Date: 2021/9/6 21:27
 * @Version: 1.0
 */
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
 *@ClassName MapSafe
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/6
 **/
public class MapSafe {
    public static void main(String[] args) {
        //Map<String,String> map = new HashMap<>();
        //Map<String, Object> map = Collections.synchronizedMap(new HashMap<>());
        Map<String, Object> map = new ConcurrentHashMap<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }
}

7、Callable

image.png

  1. 可以有返回值
  2. 可以抛出异常
  3. 方法不同,run()/call()

callable源码

image.png

image.png

image.png

image.png

代码测试

package com.zmz.callable;/**
 * @ProjectName: Juc
 * @Package: com.zmz.callable
 * @ClassName: CallableTest
 * @Author: 张晟睿
 * @Date: 2021/10/3 16:52
 * @Version: 1.0
 */
import com.sun.org.apache.bcel.internal.generic.NEW;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
 *@ClassName CallableTest
 *@Description
 *@Author 张晟睿
 *@Date 2021/10/3
 **/
public class CallableTest {
    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();
        new Thread().start();
        MyThread myThread = new MyThread();
        FutureTask futureTask = new FutureTask(myThread);//适配类
        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start(); //结果存在缓存提交效率
        Integer o = (Integer) futureTask.get();//获取返回的结果
        //这个get方法可以会产生阻塞! 解决办法 放到最后一行或者异步通信
        System.out.println(o);
    }
}
class MyThread implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("call()方法");
        //耗时操作
        return 1024;
    }
}
/*
1、有缓存
2、结果可能会等待,阻塞
*/

8、常用的辅助类

1) CountDownLatch—减法计数器

package com.zmz.assist;/**
 * @ProjectName: Juc
 * @Package: com.zmz.assist
 * @ClassName: CountDownLatchDemo
 * @Author: 张晟睿
 * @Date: 2021/10/3 18:00
 * @Version: 1.0
 */
import java.util.concurrent.CountDownLatch;
/**
 *@ClassName CountDownLatchDemo
 *@Description
 *@Author 张晟睿
 *@Date 2021/10/3
 **/
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch count = new CountDownLatch(10);
        for (int i = 1; i <= 10; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName() + "Go out");
                count.countDown();//数量-1
            },String.valueOf(i)).start();
        }
        count.await();//等计数器归零,然后再往下执行
        System.out.println("Close Door");
    }
}

原理:

  • count.countDown();//数量-1
  • count.await();//等待计数器归零。然后再向下执行

每次有线程用countDown()数量-1,如果计算器变为0了,然后count.await()就被唤醒,继续下面的执行!

2) CyclicBarrier—加法计数器

package com.zmz.assist;/**
 * @ProjectName: Juc
 * @Package: com.zmz.assist
 * @ClassName: CycilcBarrierDemo
 * @Author: 张晟睿
 * @Date: 2021/10/3 18:23
 * @Version: 1.0
 */
import com.sun.org.apache.bcel.internal.generic.NEW;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
 *@ClassName CycilcBarrierDemo
 *@Description
 *@Author 张晟睿
 *@Date 2021/10/3
 **/
public class CycilcBarrierDemo {
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        CyclicBarrier barrier = new CyclicBarrier(7,()->{
            System.out.println("你已经凑齐了七颗龙珠!可以变身了");
        });
        for (int i = 1; i <= 7; i++) {
            final int temp = i;
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+ "收集" +(temp) +"颗龙珠");
                try {
                    barrier.await();//等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

3) Semaphore

Semaphore:信号量,很多时候用来处理高并发。

image.png

package com.zmz.assist;/**
 * @ProjectName: Juc
 * @Package: com.zmz.assist
 * @ClassName: SemaphoreDemo
 * @Author: 张晟睿
 * @Date: 2021/10/3 19:32
 * @Version: 1.0
 */
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
 *@ClassName SemaphoreDemo
 *@Description
 *@Author 张晟睿
 *@Date 2021/10/3
 **/
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                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 {
                    semaphore.release();//释放
                }
            },String.valueOf(i)).start();
        }
    }
}

原理:

  • acquire():获得,假设已经满了组需要等待,直到被释放为止
  • release():释放,会将当前的信号量释放+1,然后唤醒等待的线程!
    作用:多个共享的资源互斥使用!并发限流控制最大的线程数量!

9、读写锁ReadwriteLock

image.png

package com.zmz.lock;/**
 * @ProjectName: Juc
 * @Package: com.zmz.lock
 * @ClassName: ReadwritelockDemo
 * @Author: 张晟睿
 * @Date: 2021/10/3 20:48
 * @Version: 1.0
 */
import java.util.HashMap;
import java.util.Map;
/**
 *@ClassName ReadwritelockDemo
 *@Description
 *@Author 张晟睿
 *@Date 2021/10/3
 **/
public class ReadwritelockDemo {
    public static void main(String[] args) {
        Mycache mycache = new Mycache();
        //写入
        for (int i = 1; i < 6; i++) {
            final int temp = i;
            new Thread(()->{
                mycache.put(temp+"",temp+"");
            },String.valueOf(i)).start();
        }
        //读取
        for (int i = 1; i < 6; i++) {
            final int temp = i;
            new Thread(()->{
                mycache.get(temp+"");
            },String.valueOf(i)).start();
        }
    }
}
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() + "写入完成");
    }
    public void get(String key){
        System.out.println(Thread.currentThread().getName() + "读取" + key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取完成");
    }
}
/*
1写入1
5写入5
5写入完成
4写入4
4写入完成
3写入3
2写入2
1读取1
3写入完成
1写入完成
2读取2
2读取完成
3读取3
3读取完成
1读取完成
2写入完成
5读取5
5读取完成
4读取4
4读取完成
*/

我们可以看到出现了严重的插队问题!该如何去解决囊?我们使用读写锁来解决插队的问题。

修改后的操作

package com.zmz.lock;/**
 * @ProjectName: Juc
 * @Package: com.zmz.lock
 * @ClassName: ReadwritelockDemo
 * @Author: 张晟睿
 * @Date: 2021/10/3 20:48
 * @Version: 1.0
 */
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
 * @ClassName ReadwritelockDemo
 * @Description
 * @Author 张晟睿
 * @Date 2021/10/3
 **/
/*
*独占锁 (写锁)一次只能被一个线程占有
*共享锁 (读锁)多个线程可以同时占有
* ReadWriteLock
* 读-读   可以共存
* 读-写   不可以共存
* 写-写   不可以共存
* */
public class ReadwritelockDemo {
    public static void main(String[] args) {
        MycacheLock mycache = new MycacheLock();
        //写入
        for (int i = 1; i < 6; i++) {
            final int temp = i;
            new Thread(() -> {
                mycache.put(temp + "", temp + "");
            }, String.valueOf(i)).start();
        }
        //读取
        for (int i = 1; i < 6; i++) {
            final int temp = i;
            new Thread(() -> {
                mycache.get(temp + "");
            }, String.valueOf(i)).start();
        }
    }
}
//加锁
class MycacheLock {
    private volatile Map<String, Object> map = new HashMap<>();
    //读写锁:更加细粒度的控制
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    //存、写的时候,只希望同时只有一个线程写
    public void put(String key, Object value) {
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入完成");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }
    //取、读所有人都可以进行操作
    public void get(String key) {
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "读取" + key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取完成");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.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() + "写入完成");
    }
    public void get(String key) {
        System.out.println(Thread.currentThread().getName() + "读取" + key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取完成");
    }
}
/*
1写入1
1写入完成
2写入2
2写入完成
3写入3
3写入完成
4写入4
4写入完成
5写入5
5写入完成
1读取1
1读取完成
5读取5
3读取3
3读取完成
4读取4
4读取完成
5读取完成
2读取2
2读取完成
*/

我们可以看到输出的结果在写入的时候有序的进行,读操作的时候可以无序的进行,可以看到已经到达我们预期的效果😊

10、堵塞队列

堵塞

image.png

image.png

image.png

image.png

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

10.1 学会使用队列

添加、移除元素,现在有四组API

1) 四组API

方法 抛出异常 不会抛出异常,有返回值 阻塞等待 超时等待
添加 add() offer() put() offer(E e, long timeout, TimeUnit unit)
移除 remove() poll() take() poll(long timeout, TimeUnit unit)
判断首部 element() peek() - -
/*
* 抛出异常
* */
    public static void test1(){
        //队列大小3
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));
        //IllegalState ExceptionQueue full  抛出异常
        //System.out.println(blockingQueue.add("d"));
        //检测队首元素
        System.out.println(blockingQueue.element());                                                 System.out.println("================================================");
        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(){
        //队列大小3
        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("================================================");
        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 {
        //队列大小3
        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() throws InterruptedException {
        //队列大小3
        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());
        blockingQueue.poll(2,TimeUnit.SECONDS);
    }

2) SynchronizedQueue 同步队列

没有容量,进去一个元素,必须等待取出来之后,才能再往里面放一个元素

put take

package com.zmz.queue;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.queue
 * @ClassName: SyncQueue
 * @Author: 张晟睿
 * @Date: 2021/10/8 14:18
 * @Version: 1.0
 */
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/**
 * 同步队列
 * 和其他的lockQueue 不一样, SynchronousQueue 不存储元素
 */
public class SyncQueue {
    public static void main(String[] args) {
        SynchronousQueue<String> synchronousQueue = new SynchronousQueue<>(); //同步队列
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName() + "put 1");
                synchronousQueue.put("1");
                System.out.println(Thread.currentThread().getName() + "put 2");
                synchronousQueue.put("2");
                System.out.println(Thread.currentThread().getName() + "put 3");
                synchronousQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"Thread1").start();
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "=>" + synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "=>" + synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "=>" + synchronousQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
            }
        },"Thread2").start();
    }
}
/*
Thread1put 1
Thread2=>1
Thread1put 2
Thread2=>2
Thread1put 3
Thread2=>3
*/

11、线程池

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

程序的运行,本质: 占用系统的资源 ! 优化CPU资源的使用 ===>池化技术

线程池, 连接池, 内存池, 对象池///…

池化技术: 实现准备好一些资源, 有人要用,就来我这里拿,用完之后还给我

1) 线程池的好处:

  1. 降低资源消耗
  2. 提高响应速度
  3. 方便管理

线程复用,可以控制最大并发数,管理线程

2) 线程池: 三大方法

  • ExecutorService service = Executors.newSingleThreadExecutor();//单个线程
  • ExecutorService service = Executors.newFixedThreadPool(5);//创建一个固定的线程池的大小
  • ExecutorService service = Executors.newCachedThreadPool();//可伸缩的,
package com.zmz.Pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.ThreadPool
 * @ClassName: ThreadPool
 * @Author: 张晟睿
 * @Date: 2021/10/8 16:44
 * @Version: 1.0
 */
public class ThreadPool {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
        ExecutorService threadPool2 = Executors.newFixedThreadPool(5); //创建一个固定的线程池的大小
        ExecutorService threadPool3 = Executors.newCachedThreadPool(); //可伸缩的
        //线程池用完必须要关闭线程池
        try {
            for (int i = 1; i <=100 ; i++) {
                //通过线程池创建线程
                threadPool3.execute(()->{
                    System.out.println(Thread.currentThread().getName()+ " ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool3.shutdown();
        }
    }
}

3) 七大参数

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.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

image.png

image.png

package com.zmz.Pool;
import java.util.concurrent.*;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.Pool
 * @ClassName: ThreadPoolExecutorTest
 * @Author: 张晟睿
 * @Date: 2021/10/8 16:59
 * @Version: 1.0
 */
public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        // 获取cpu 的核数
        int max = Runtime.getRuntime().availableProcessors();
        ExecutorService service =new ThreadPoolExecutor(
                2,//核心线程池大小
                max,//最大的线程池大小
                3,//超时了没有人调用就会释放
                TimeUnit.SECONDS,//超时单位
                new LinkedBlockingDeque<>(3),//阻塞队列
                Executors.defaultThreadFactory(),//线程工厂 创建线程的
                new ThreadPoolExecutor.AbortPolicy()//拒绝策略
        );
        try {
            for (int i = 1; i <= 5; i++) {
                service.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "运行成功");
                });
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            service.shutdown();
        }
    }
}

4) 拒绝策略

image.png

  • new ThreadPoolExecutor.AbortPolicy() 超出最大处理线程抛出异常
  • new ThreadPoolExecutor.CallerRunsPolicy() 从哪个线程创建就由那个线程执行
  • new ThreadPoolExecutor.DiscardPolicy() 队列满了不会抛出异常
  • new ThreadPoolExecutor.DiscardOldestPolicy() 尝试去和第一个竞争,也不会抛出异常

12、四大函数式接口

新时代的程序员👨‍💻:lambda表达式、链式编程、函数式接口、Stream流式计算

image.png

1) Function函数型接口

image.png

package com.zmz.FourFunction;
import java.util.function.Function;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.FourFunction
 * @ClassName: functionDemo
 * @Author: 张晟睿
 * @Date: 2021/10/8 17:15
 * @Version: 1.0
 */
public class functionDemo {
    public static void main(String[] args) {
        Function<String, String> function = (str) -> {
            return str;
        };
        System.out.println(function.apply("Hello,zmz!"));
    }
}

2) Predicate 断定型接口

image.png

package com.zmz.FourFunction;
import java.util.function.Predicate;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.FourFunction
 * @ClassName: PredicateDemo
 * @Author: 张晟睿
 * @Date: 2021/10/8 17:18
 * @Version: 1.0
 */
public class PredicateDemo {
    public static void main(String[] args) {
        Predicate<String> predicate = (str) -> {return str.isEmpty();};
        // false
        System.out.println(predicate.test("zmz"));
        // true
        System.out.println(predicate.test(""));
    }
}

3) Suppier 供给型接口

image.png

package com.zmz.FourFunction;
import java.util.function.Supplier;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.FourFunction
 * @ClassName: SuppierDemo
 * @Author: 张晟睿
 * @Date: 2021/10/8 17:21
 * @Version: 1.0
 */
public class SuppierDemo {
    public static void main(String[] args) {
        Supplier<String> supplier = ()->{return "1024";};
        System.out.println(supplier.get());
    }
}

4) Consummer 消费型接口

image.png

package com.zmz.FourFunction;
import java.util.function.Consumer;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.FourFunction
 * @ClassName: ConsummerDemo
 * @Author: 张晟睿
 * @Date: 2021/10/8 17:21
 * @Version: 1.0
 */
public class ConsummerDemo {
    public static void main(String[] args) {
        Consumer<String> consumer = (str)->{
            System.out.println(str);
        };
        consumer.accept("zmz");
    }
}

13、Stream 流式计算

package com.zmz.Stream;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.Stream
 * @ClassName: User
 * @Author: 张晟睿
 * @Date: 2021/10/8 18:01
 * @Version: 1.0
 */
public class User {
    private int id;
    private String name;
    private int age;
    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
package com.zmz.Stream;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.Stream
 * @ClassName: StreamDemo
 * @Author: 张晟睿
 * @Date: 2021/10/8 18:00
 * @Version: 1.0
 *
 * * 题目要求: 用一行代码实现
 *  * 1. Id 必须是偶数
 *  * 2.年龄必须大于23
 *  * 3. 用户名转为大写
 *  * 4. 用户名倒序
 *  * 5. 只能输出一个用户
 */
import java.util.Arrays;
import java.util.List;
public class StreamDemo {
    public static void main(String[] args) {
        User u1 = new User(1, "a", 23);
        User u2 = new User(2, "b", 23);
        User u3 = new User(3, "c", 23);
        User u4 = new User(6, "d", 24);
        User u5 = new User(4, "e", 25);
        List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
        // lambda、链式编程、函数式接口、流式计算
        list.stream()
                .filter(user -> {return user.getId()%2 == 0;})
                .filter(user -> {return user.getAge() > 20;})
                .map(user -> {return user.getName().toUpperCase();})
                .sorted((user1, user2) -> {return user2.compareTo(user1);})
                .limit(1)
                .forEach(System.out::println);
    }
}

14、ForkJoin—多线并发处理框架

什么是ForkJoin?

ava.util.concurrent.ForkJoinPool由Java大师Doug  Lea主持编写,它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。本文中对Fork/Join框架的讲解,基于JDK1.8+中的Fork/Join框架实现,参考的Fork/Join框架主要源代码也基于JDK1.8+。

这几篇文章将试图解释Fork/Join框架的知识点,以便对自己、对各位读者在并发程序的设计思路上进行一些启发。文章将首先讲解Fork/Join框架的基本使用,以及其中需要注意的使用要点;接着使用Fork/Join框架解决一些实际问题;最后再讲解Fork/Join框架的工作原理。

image.png

1)ForkJoin 特点: 工作窃取!

image.png

2)如果使用ForkJoin

第一步,通过ForkJoinPool来执行

第二步,计算任务 execute(ForkJoinTask<?> task)

第三步,计算类要去继承ForkJoinTask

ForkJoin 的计算类

ForkJoinComputer.java

package com.zmz.ForkJoin;
import java.util.concurrent.RecursiveTask;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.ForkJoin
 * @ClassName: ForkJoinComputer
 * @Author: 张晟睿
 * @Date: 2021/10/9 15:17
 * @Version: 1.0
 */
public class ForkJoinComputer extends RecursiveTask<Long> {
    private long start;
    private long end;
    /** 临界值 */
    private long temp = 1000000L;
    public ForkJoinComputer(long start, long end) {
        this.start = start;
        this.end = end;
    }
    /**
     * 计算方法
     * @return
     */
    @Override
    protected Long compute() {
        if ((end - start) < temp) {
            Long sum = 0L;
            for (Long i = start; i < end; i++) {
                sum += i;
            }
            return sum;
        }else {
            // 使用ForkJoin 分而治之 计算
            //1 . 计算平均值
            long middle = (start + end) / 2;
            ForkJoinComputer forkJoinDemo1 = new ForkJoinComputer(start, middle);
            // 拆分任务,把线程压入线程队列
            forkJoinDemo1.fork();
            ForkJoinComputer forkJoinDemo2 = new ForkJoinComputer(middle, end);
            forkJoinDemo2.fork();
            long taskSum = forkJoinDemo1.join() + forkJoinDemo2.join();
            return taskSum;
        }
    }
}

测试类 ForkJoinTest.java

package com.zmz.ForkJoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.ForkJoin
 * @ClassName: ForkJoinTest
 * @Author: 张晟睿
 * @Date: 2021/10/9 15:18
 * @Version: 1.0
 */
public class ForkJoinTest {
    private static final long SUM = 20_0000_0000;
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        test1();
        test2();
        test3();
    }
    /**
     * 使用普通方法
     */
    public static void test1() {
        long star = System.currentTimeMillis();
        long sum = 0L;
        for (long i = 1; i < SUM ; i++) {
            sum += i;
        }
        long end = System.currentTimeMillis();
        System.out.println(sum);
        System.out.println("普通程序猿——时间:" + (end - star));
        System.out.println("============================");
    }
    /**
     * 使用ForkJoin 方法
     */
    public static void test2() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoinComputer(0L, SUM);
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);
        Long along = submit.get();
        System.out.println(along);
        long end = System.currentTimeMillis();
        System.out.println("中级程序猿——时间:" + (end - start));
        System.out.println("--------------");
    }
    /**
     * 使用 Stream 流计算
     */
    public static void test3() {
        long start = System.currentTimeMillis();
        long sum = LongStream.range(0L, 20_0000_0000L).parallel().reduce(0, Long::sum);
        System.out.println(sum);
        long end = System.currentTimeMillis();
        System.out.println("高级程序猿——时间:" + (end - start));
        System.out.println("--------------");
        System.out.println("============================");
    }
}

image.png

分析一下高级程序猿的处理:

image.png

.parallel().reduce(0, Long::sum)使用一个并行流去计算整个计算,提高效率。

目录
相关文章
|
3天前
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
2天前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
7天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
16天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
13天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
16天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
16天前
|
安全 Java 编译器
Java多线程编程的陷阱与最佳实践####
【10月更文挑战第29天】 本文深入探讨了Java多线程编程中的常见陷阱,如竞态条件、死锁、内存一致性错误等,并通过实例分析揭示了这些陷阱的成因。同时,文章也分享了一系列最佳实践,包括使用volatile关键字、原子类、线程安全集合以及并发框架(如java.util.concurrent包下的工具类),帮助开发者有效避免多线程编程中的问题,提升应用的稳定性和性能。 ####
44 1
|
20天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
21天前
|
Java 开发者
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
44 4
|
21天前
|
消息中间件 供应链 Java
掌握Java多线程编程的艺术
【10月更文挑战第29天】 在当今软件开发领域,多线程编程已成为提升应用性能和响应速度的关键手段之一。本文旨在深入探讨Java多线程编程的核心技术、常见问题以及最佳实践,通过实际案例分析,帮助读者理解并掌握如何在Java应用中高效地使用多线程。不同于常规的技术总结,本文将结合作者多年的实践经验,以故事化的方式讲述多线程编程的魅力与挑战,旨在为读者提供一种全新的学习视角。
48 3

热门文章

最新文章

下一篇
无影云桌面