JUC高并发编程

JUC 高并发编程的入门学习 课程内容概览 什么是 JUC Lock 接口 线程间通信 集合的线程安全 多线程锁 Callable 接口 JUC 三大辅助类: CountDownLatch CyclicBarrier Semaphore 读写锁: ReentrantReadWriteLock 阻塞队列 ThreadPool 线程池 Fork/Join 框架 CompletableFuture 1 什么是 JUC 1.1 JUC 简介 在 Java 中,线程部分是一个重点,本篇文章说的 JUC 也是关于线程的。JUC就是 java.u 阅读详情

JUC概述

1.1 JUC简介

  • java.util.concurrent包名的简写,是关于并发编程的API
  • 与JUC相关的有三个包:java.util.concurrent、java.util.concurrent.atomic、java.util.concurrent.locks

1.2 进程和线程

  • 进程:系统中一个正在运行的应用程序;一个程序就是一个进程;进程操作系统资源分配的最小单位
  • 线程:系统分配处理器时间资源的基本单位;进程之内独立执行的一个单元执行流。线程是程序执行的最小单位

1.3 线程的状态

1.3.1 线程状态枚举

1.3.2 wait、sleep区别

  • sleep是Thread的静态方法。wait是Object的方法,任何对象实例都能调用。
  • sleep不会释放锁,它也不需要占用锁。wait会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized中)。
  • 都可以呗interrupted方法中断。

1.4 并发和并行

1.4.1 串行模式

  • 所有任务都按先后顺序执行。一次只能取得一个任务,执行完成这个任务才能执行下一个任务。

1.4.2 并行模式

  • 多个任务同时进行。可以同时取得多个任务,并同时去执行这些任务。

1.4.3 并发

  • 并发:同一时刻多个线程在访问同一个资源,多个线程对一个点。例如:春运抢票 电商秒杀
  • 并行:多项工作一起执行,之后再汇总。例如:泡方便面,电水壶烧水,一边撕调料倒入桶中

1.4.5 小结(重点)

1.5 管程

  • 管理共享变量以及对其操作过程,让它们支持并发访问。也就是管理类的成员变量和成员方法,让这个类是线程安全的。

1.6 用户线程和守护线程

  • 用户线程(自定义线程):主线程结束了,用户线程还在执行,JVM存活,可以通过线程的setDaemon(true)方法设置线程为守护线程
  • 守护线程(垃圾回收):没有用户线程了,都是守护线程,JVM结束

2. Lock接口

2.1 Synchronized关键字

2.1.1 synchronized概述

synchronized{
	...
}

是java中的关键字,是一种同步锁

  1. 修饰代码块,被修饰的代码块为同步代码块,作用范围为{}内,作用对象是调用这个代码块的对象
  2. 修饰方法,被修饰的方法为同步方法,作用范围为整个方法,作用对象是调用这个方法的对象
  • 虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,故synchronized关键字不能被继承。如果在父类的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,那么子类中的这个方法默认情况下是不同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。
  • 当然,还可以在子类中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类同步方法,因此,子类到方法也相当于同步了
  1. 修饰静态方法,作用范围是整个静态方法,作用对象是这个类的所有对象
  2. 修饰类,作用范围是synchronized后面括号起来的部分,作用的对象是这个类的所有对象

2.1.2 模拟卖票

class Ticket {
    // 票数
    private int number = 100;

    // 卖票
    public synchronized void sale() {
        if (number > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出第:" + (number--) + " 剩下:" + number);
        }
    }

}

public class TicketMain {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i<100; i++){
                    ticket.sale();
                }
            }
        }, "AA").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i<100; i++){
                    ticket.sale();
                }
            }
        }, "BB").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i<100; i++){
                    ticket.sale();
                }
            }
        }, "CC").start();
    }
}

2.1.3 多线程编程步骤(上)

  1. 创建资源类,创建属性和操作方法
  2. 创建多线程调用资源类的方法

2.2 Lock接口

  • 属于java.util.concurrent.locks包下,为锁和等待条件提供一个框架的接口和类,它不同与内置同步和监视器
  • Lock实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作

2.2.1 synchronized和Lock的区别

  • synchronized是Java的关键字。在JVM层面上,而Lock是一个类
  • synchronized发生异常会自动释放锁,因此不会导致死锁的现象发生。Lock发生异常需要主动释放锁,否则会发生死锁。
  • synchronized不能够响应中断,等待的线程会一直等待。Lock可以让等待锁的线程响应中断。
  • synchronized不能获取锁的状态。Lock可以知道是否成功获取锁。
  • Lock可以提高多个线程进行读操作的效率。

竞争资源不激烈两者性能相当,而竞争资源激烈时(大量线程同时竞争),Lock性能远远优于synchronized。

在这里插入图片描述

Lock锁模拟卖票
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Ticket {
    // 票数
    private int number = 100;

    Lock lock = new ReentrantLock();

    // 卖票
    public synchronized void sale() {
        try{
            // 获取锁
            lock.lock();
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出第:" + (number--) + " 剩下:" + number);
            }
        }finally {
            // 释放锁
            lock.unlock();
        }
    }

}

public class LTicketMain {

    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        new Thread(()->{
            for(int i = 0; i<100; i++){
                ticket.sale();
            }
        }, "AA").start();

        new Thread(()->{
            for(int i = 0; i<100; i++){
                ticket.sale();
            }
        }, "BB").start();

        new Thread(()->{
            for(int i = 0; i<100; i++){
                ticket.sale();
            }
        }, "CC").start();
    }
}

细节

  • 线程调用start()方法不一定会马上创建,具体什么时候创建由操作系统决定。操作系统空闲时会立马创建线程,不空闲会等一会创建线程。

2.3 创建线程的四种方式

  • 继承Thread类
  • 实现Runnable接口
  • 使用Callable接口
  • 是一个线程池

3. 线程间通信

初始化变量i=0,i=0时线程A对i+1,i !=0,线程B对i-1

synchronized

public class Share {
    private int i = 0;

    // 加一
    public synchronized void incr() throws InterruptedException {
        while(i != 0){
            this.wait();
        }
        i++;
        System.out.println(Thread.currentThread().getName() + "::"+ i);
        this.notifyAll();

    }

    // 减一
    public synchronized void decr() throws InterruptedException {
        while(i == 0){
            this.wait();
        }
        i--;
        System.out.println(Thread.currentThread().getName() + "::"+ i);
        this.notifyAll();
    }

    public static void main(String[] args) {
        Share share = new Share();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        // 增加多一个用来测试虚假唤醒
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
    }
}

Lock

public class Share {
    private int i = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    // 加一
    public void incr() throws InterruptedException {
        lock.lock();
        try{
            while (i != 0) {
                condition.await();
            }
            i++;
            System.out.println(Thread.currentThread().getName() + "::" + i);
            condition.signalAll();
        }finally {
            lock.unlock();
        }

    }

    // 减一
    public void decr() throws InterruptedException {
        lock.lock();
        try{
            while (i == 0) {
                condition.await();
            }
            i--;
            System.out.println(Thread.currentThread().getName() + "::" + i);
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        Share share = new Share();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        // 增加案例测试虚假唤醒
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();

    }
}

注意: 当while条件换成if条件会造成虚假唤醒的情况,i会出现负数

虚假唤醒导致if在多线程环境下出错,因为它不再判断条件是否满足,继续从wait()方法之后执行。而while还会再次判断条件是否满足,如果不满足就不会执行。

4. 线程间定制化通信

Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。
Condition是个接口,基本的方法就是await()和signal()方法;
Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用

Conditon中的await()对应Object的wait();
Condition中的signal()对应Object的notify();
Condition中的signalAll()对应Object的notifyAll()。
在这里插入图片描述

让ABC线程按照指定顺序执行

public class ShareResource {

    private int flag = 1;
    private final Lock lock = new ReentrantLock();
    private final Condition c1 = lock.newCondition();
    private final Condition c2 = lock.newCondition();
    private final Condition c3 = lock.newCondition();

	// 打印5次
    public void print5(int loop) throws InterruptedException {
        lock.lock();
        try {
            while (flag != 1) {
                c1.await();
            }
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + "::" + i + " 轮数:" + loop);
            }
            flag = 2;
            // 通知B线程
            c2.signal();
        } finally {
            lock.unlock();
        }
    }

	// 打印10次
    public void print10(int loop) throws InterruptedException {
        lock.lock();
        try {
            while (flag != 2) {
                c2.await();
            }
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName() + "::" + i + " 轮数:" + loop);
            }
            flag = 3;
            // 通知C线程
            c3.signal();
        } finally {
            lock.unlock();
        }
    }

	// 打印15次
    public void print15(int loop) throws InterruptedException {
        lock.lock();
        try {
            while (flag != 3) {
                c3.await();
            }
            for (int i = 1; i <= 15; i++) {
                System.out.println(Thread.currentThread().getName() + "::" + i + " 轮数:" + loop);
            }
            flag = 1;
            // 通知A线程
            c1.signal();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        // 创建三个线程分别调用每个方法
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    shareResource.print5(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    shareResource.print10(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    shareResource.print15(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
    }
}

5. 集合的线程安全

5.1 集合线程不安全演示

多个线程同时向list插入元素会出现线程不安全问题,因为ArrayList<>()是线程不安全的

public class ListDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

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

5.2 ArrayList解决方案

Vector

List<String> list= new Vector<>();
  • 在方法上加上了synchronized关键字实现线程安全,但是效率低下
  • 在这里插入图片描述

Collections

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

Collections.synchronizedList(List list) 返回的是一个 SynchronizedList 的对象,SynchronizedList 的实现里,get, set, add 等操作都加了 mutex(互斥) 对象锁,再将操作委托给最初传入的 list。这个对象以组合的方式将对 List 的接口方法操作,委托给传入的 list 对象,并且对所有的接口方法对象加锁,得到并发安全性。
这就是以组合的方式,将非线程安全的对象,封装成线程安全对象,而实际的操作都是在原非线程安全对象上进行,只是在操作前给加了同步锁。

CopyOnWriteArrayList

List<String> list = new CopyOnWriteArrayList<>();

底层原理

  • 并发读,独立写:读的时候是读原数组,写的时候会copy新的数组,在新的数组上进行操作,然后和原数组合并,再次读会读到合并后的数组。
  • 在这里插入图片描述

5.3 HashSet线程不安全

HashMap底层就是HashMap

  • 使用CopyOnWriteArraySet
Set<String> set = new CopyOnWriteArraySet<>();

5.4 HashMap线程不安全问题

  • ConcurrentHashMap
 Map<String, String> map = new ConcurrentHashMap<>();

6. 多线程锁

6.1 锁的八种情况

synchronized实现同步的基础:Java中每一个对象都可以作为锁。
具体表现为三种形式:

  • 对于普通同步方法,锁谁当前实例对象(this)
  • 对于静态同步方法,锁是当前类的Class对象
  • 对于同步方法块,锁是synchronized括号里配置的对象

6.2 公平锁和非公平锁

公平和非公平相对于线程资源竞争来说,非公平则一个资源独占锁直到任务结束,其他线程会处于饿死的状态。

非公平锁:其他线程会饿死,但效率高
公平锁:线程平等,效率相对低

private Lock lock1 = new ReentrantLock(false);   // 非公平锁 (默认为false)
private Lock lock2 = new ReentrantLock(true);   // 公平锁

6.3 可重入锁

某个线程已经获得某个锁,可以再次获取锁而不会出现死锁

synchronized是隐式 Lock是显式的可重入锁

注意:Lock执行了多少次上锁,就必须解锁多少次,否则导致其他线程无法获取锁。

6.4 死锁

两个或两个以上的进程在执行过程中,因为争夺资源造成一种互相等待的现象。如果没有外力干涉,则程序无法执行下去。

死锁产生的原因

  • 系统功能资源不足
  • 进程运行推进顺序不合适
  • 资源分配不当

验证是否是死锁

  • jps 类似linux ps -ef
  • jstack jvm自带堆栈跟踪工具

7. Callable接口

Callable与Runnable的区别:

  • Callable通过call方法获取具体的返回值,这个返回值具体是通过实现Future接口对象的get方法获取的,该方法会造成现场阻塞。Runnable的run方法没有返回值
  • Callable的call方法可以抛出异常,可以通过捕获异常处理。Runnable的run方法不可以抛出异常,异常要在run方法内部必须得到处理,不能向外界抛出。

Callable使用

  • FutureTask类实现了RunnableFuture接口,而RunnableFuture接口实现了Runnable和Future接口

方法1: 创建一个FutureTask对象,传入Callable接口的实现类,并实现Callable接口的call方法,通过FutureTask的get方法可以获取到任务的返回值

public class CallableTest {
	public static void main(String[] args) {
		// 方式1
        FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());

        new Thread(futureTask, "A").start();

        System.out.println(futureTask.get());	// 1
		
		// 方式2 匿名函数
		FutureTask<Integer> futureTask2 = new FutureTask<>(() -> {
            System.out.println(Thread.currentThread().getName());
            return 200;
        });
		new Thread(futureTask2, "B").start();

        System.out.println(futureTask2.get());	// 200
  
	}
	

}

class MyCallable implements Callable<Integer> {
	@Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        return 1;
    }
}

FutureTask支持Callable的匿名函数源码
在这里插入图片描述
在这里插入图片描述

8. JUC强大的辅助类

8.1 减少计数CountDownLatch

CountDownLatch类可以设置一个计数器,然后通过countDown方法来进行减1的操作,使用await方法等待计数器不大于0,然后继续执行await方法之后的语句

  • CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞
  • 其他线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞)
  • 当计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行

模拟全部同学离开教室后,最后班长才可以锁门

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(5);

        // 模拟同学陆续离开教室
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "同学离开教室");

                // 计数器减一
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }

        countDownLatch.await();
        System.out.println("main班长锁门");
    }

在这里插入图片描述

8.2 循环栅栏CyclicBarrier

CyclicBarrier是循环阻塞的意思,在使用中CyclicBarrier的构造方法第一个参数是目标障碍数,每次执行CyclicBarrier一次障碍数就加一,如果达到了目标障碍数,才会执行cyclicBarrier.await()之后的语句。可以将CyclicBarrier理解为加一的操作。

集齐七龙珠后才可以召唤神龙

    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("七龙珠集齐了,开始召唤神龙");
        });

        // 模拟同学陆续离开教室
        for (int i = 1; i <= 7; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "星龙珠被收集到了");
                    // 等待
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
        
    }

在这里插入图片描述

8.3 信号灯Semaphore

一个计数信号量。可以通过Semaphore构造方法设置许可数量,调用acquire()方法可以获得许可,release()方法释放许可。当没有获取许可时,其他线程处于阻塞或等待状态,只有当获取许可后才能继续执行操作。

6辆汽车,停到3个车位

    public static void main(String[] args) throws InterruptedException {

        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(new Random().nextInt(3));

                    System.out.println(Thread.currentThread().getName() + "车离开了车位-------");

                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    // 释放
                    semaphore.release();
                }

            }, String.valueOf(i)).start();
        }
    }

在这里插入图片描述

9. ReentrantReadWriteLock读写锁

读锁:共享锁,会发生死锁
写锁:独占锁,会发生死锁

JUC高并发编程从入门到精通(全) 目录前言 前言 在了解这部分内容的时候 先要了解java的一些基础内容 java零基础从入门到精通(全) javaSE从入门到精通(全) 所谓JUC是java.util .concurrent 工具包的简称这是一个处理线程的工具包可以实现多线程高并发的内容 了解该部分内容先了解线程与进程的相关概念 【操作系统】线程与进程的深入剖析(全) java之Thread类详细分析(全) 以及涉及到的lambda表达式函数的概念 java中lambda表达式 ...... 阅读详情

相关推荐

Ansys EMC Plus:用于仿真屏蔽效果的一键式工作流程

在 EMA3D 选项卡下,单击 Shielding Effectiveness 按钮下方的箭头以访问设置并使用所需数量的分割数启动工作流程,这些分割数定义了网格大小。在此示例中,设置了 35 个分段,提供了良好的 FDTD 网格,同时保持了较短的仿真运行时间。接下来,选择默认的平面波源文件,然后选择所需的分析方向。您还可以查看和调整仿真树中的仿真参数,包括定义最低和最高频率值的解域、入射平面波的极化以及探针设置。您可以控制屏蔽效果图设置,并以线性比例显示结果。仿真完成后,软件将绘制与频率相关的屏蔽效果图。

jkh920184196的博客 872

007-多线程-锁-JUC锁-CountDownLatch-闭锁【允许一个或多个线程,等待其他一组线程完成操作,再继续执行】...

一、概述     CountDownLatch是JAVA提供在java.util.concurrent包下的一个辅助类,指定的一个或多个线程等待其他线程执行完成后执行。   能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。   闭锁是一种同步工具类,可以延迟线程的进度,直到其到达终止状态。闭锁的作...

dilv4062的博客 197

避开ns-3学习深坑:用sns3模块快速搭建GEO卫星通信仿真(附GitHub代码解读)

本文介绍了如何使用sns3模块快速搭建GEO卫星通信仿真环境,绕过复杂的ns-3底层细节。通过详细的Linux环境配置、sns3模块安装和示例代码解读,帮助开发者快速上手卫星通信仿真,并提供了常见问题的解决方案和性能优化技巧。

weixin_28720573的博客 438

多线程如何等待所有子线程一起完成任务后再执行主线程

多线程如何等待所有子线程一起完成任务后再执行主线程 1、使用线程类自带的join方法,将子线程加入到主线程,在子线程执行完之后,在执行主线程逻辑。 public static void joinDemo() throws InterruptedException { System.out.println("=========Test with join====="); JoinWorker worker1 = new JoinWorker("worke

weixin_44860609的博客 4336

合规批量下载美国上市公司年报数据的一些经验和总结

本文总结了使用Python脚本批量下载和处理美国上市公司SEC报告的技术经验。通过CIK代码查询SEC EDGAR系统,生成特定日期和报告类型的URL,并使用Selenium和Requests库下载报告内容。流程包括数据获取、文件下载、Excel处理和多线程优化,确保高效处理几百条数据。关键技术挑战包括SEC访问限制、动态网页内容和数据完整性,解决方案包括设置合规的User-Agent、使用Selenium模拟浏览器行为以及错误日志记录。最佳实践包括模块化设计、多线程优化和严格遵守SEC合规性。该自动化流程

jyfool的博客 1634

SAP-MM-采购过账接口(与WMS集成)-代码

1、判断传入值非空检验; 2、判断过账日期是否允许在当前期间; 3、判断是否为集采订单业务,是否审批完成; 4、判断是否发布标准成本发布(此业务场景与价格控制3+S有关) 5、保存日志表; 6、判断业务公司订单审批状态; 7、创建STO交货单、集采公司订单过账、STO公司间创建交货单、交货单过账(两步法)、过账失败回滚(冲销交货、删除交货单、冲销集采入库)

qq_32198063的博客 420

高并发 基础 概念

单线程 : 一定等之前请求处理完毕,才可以处理下一个请求。 多线程 : 之前的请求如果阻塞,可以直接继续发送下一个请求,而不必等待之前的请求结束。 定律:一个CPU核心在同一个时间片里,只能执行一个程序任务。 双核心CPU在同一个时间片里,可以执行两个程序任务(多任务) 双核心四线程(超线程技术Intel):一个核心有两个逻辑处理器 并行 : 多个CPU核心同时执行多个任务(C...

qq_31508695的博客 254

Python爬虫实战:东方财富股吧与雪球舆情数据实时爬取与情绪指标挖掘

本文详细介绍如何使用Python爬虫技术实时爬取东方财富股吧和雪球平台的讨论数据,结合股价波动构建情绪分析指标。我们将使用最新的异步爬虫技术、自然语言处理方法和可视化工具,为量化交易提供数据支持。文章包含完整的代码实现和技术细节,适合有一定Python基础的读者学习。

2201_76125261的博客 1222

高并发 - 基础

同步/异步、阻塞/非阻塞 同步/异步是 API 被调用者的通知方式。阻塞/非阻塞则是 API 调用者的等待方式(线程挂机/不挂起)。 同步非阻塞 Future方式,任务的完成要主线程自己判断。如NIO,后台有多个任务在执行(非阻塞),主动循环查询(同步)多个任务的完成状态,只要有任何一个任务完成,就去处理它。这就是所谓的 “I/O 多路复...

weixin_33716557的博客 124

大模型之Spring AI实战系列(二十六):Spring Boot + DeepSeek 实战指南:构建AI聊天应用

在人工智能技术飞速发展的今天,大型语言模型已经成为了推动技术创新的重要力量。DeepSeek作为国内领先的大型语言模型提供商,其推出的DeepSeek系列模型在多个领域都展现出了卓越的性能。本文将详细介绍如何使用Spring Boot框架集成DeepSeek API,构建一个简单的AI聊天应用。我们将实现两个核心功能:普通文本生成和流式文本生成。

寻道AI,探索AI无限可能! 2255

华为OD机试 - TLV格式(Python/JS/C/C++ 2025 C卷 100分)

两端通过TLV格式的报文来通信,现在收到对端的一个TLV格式的消息包,要求生成匹配后的(tag,length,valueOffset)列表。和需要匹配的n个tag对应的n行匹配结果,每一行由长度和偏移量组成。第二行:需要匹配的tag数量n(0 < n < 1000)后面N行:需要匹配n个tag值(十进制表示),递增排列。标签10(0A)存在,长度3,valueOffset=2。标签15(0F)长度4,valueOffset=2。标签14(0E)长度2,valueOffset=8。

学Java,找哪吒 2037

JUC高并发编程详解

首先,让我们认识一下JUC。JUC是Java 5引入的一个包,旨在提供更强大的并发编程支持。可以把它想象成一座丰富多彩的工具库,里面有各种各样的工具,帮助我们轻松应对并发的各种问题。JUC提供了丰富的工具和框架,帮助开发者更轻松地应对高并发编程的挑战。从线程池、原子操作、并发工具类到线程安全容器和异步编程,每个组件都为我们提供了强大的功能。通过深入理解并合理使用这些工具,我们能够编写出高效、安全且易维护的高并发程序。高并发编程可能是一项复杂的任务,但通过学习和实践,我们可以逐步掌握其中的要点。

繁依Fanyi的博客 1261

数学建模学习(120):使用Python实现基于AHP的供应商选择分析

使用Python实现基于AHP的供应商选择分析

全栈川川 909

高级技术之 JUC 高并发编程

JUC

qq_40823822的博客 534

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

JUC 高并发编程之什么是 JUC

JUC 高并发编程之什么是 JUC JUC 简介 在 Java 中,线程部分是一个重点, JUC 也是关于线程的。JUC就是 java.util .concurrent 工具包的简称。这是一个处理线程的工具包,JDK 1.5 开始出现的 进程与线程 进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的 描述,进程是程序的实体。是计算机中的

IT枫斗者的博客 384

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

JUC高并发编程4:集合的线程安全

本文是尚硅谷JUC高并发教程中集合的线程安全章节的学习笔记。包括ArrayList线程不安全演示及解决方案、HashSet线程不安全演示及解决方案、HashMap线程不安全及解决方案。供个人学习使用。

专注Java和MySQL领域知识分享 1551

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Java高并发编程:JUC与锁机制详解

Java并发编程(JUC)核心知识摘要 JUC(java.util.concurrent)是Java处理高并发的核心工具包,主要包括以下内容: 锁机制 提供ReentrantLock、ReadWriteLock等更灵活的锁实现 synchronized底层通过锁升级优化性能(偏向锁→轻量级锁→重量级锁) 并发集合 线程安全的集合类:ConcurrentHashMap、CopyOnWriteArrayList等 支持不同并发场景(读多写少/高并发读写) 线程管理 Executors框架实现线程池管理 Thre

weixin_74201783的博客 1380

【JUC高并发编程】—— 初见JUC

介绍了JUC、进程、线程、Lcok接口、Synchronized关键字、以及线程定制化通信等

欢迎来到我的世界 993

JUC高并发编程一

JUC高并发编程 1、JUC简介 在Java中,线程部分是一个重点,JUC:就是Java.util.concurrent工具包的检查,这是一个处理线程的工具包,JDK1.5开始出现 进程与线程: 进程:之在系统中正在运行的一个应用程序;程序一旦运行就是进程,进程--资源分配的最小单元 线程:系统分配处理器时间资源的基本单元或者说是进程之内独立执行的一个执行流。程序执行的最小单位。 线程的状态: New 新建 Runnable 准备就绪 Blocked 阻塞

CodeTip 244

JUC 高并发编程

JUC 学习笔记

KK's blog 776

深入JUC(高并发编程)

文章目录JUC背景JUC的结构Lock锁线程之间的通信问题synchronized实现JUC实现并发集合第一代并发第二代并发第三代并发Callable接口常见工具类CountDownLatchCyclicBarrierSemaphore读写锁(ReadWriteLock)阻塞队列线程池三大方法CachedThreadPoolSingleThreadPoolFixedThreadPool七大参数四种拒绝策略1.AbortPolicy2.CallerRunsPolicy3.DiscardOldestPolicy

qq_45738291的博客 4319
上一篇: MySQL基础笔记(一)
下一篇: 二叉树深度优先搜索(DFS)- Java
hanlin-hl
博客等级 码龄8年 3粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

hanlin-hl

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

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

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

打赏作者

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

抵扣说明:

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

余额充值