juc并发编程

RTOS任务调度原理:高优先级任务为何在低优先级任务执行时无法响应 实时操作系统(RTOS)的核心在于其确定性的任务调度机制,它通过优先级抢占确保关键任务及时执行。其基本原理是调度器仅在特定调度点(如任务主动阻塞、中断退出时)运行,比较就绪态任务的优先级并切换上下文。这一机制的技术价值在于为嵌入式系统提供可预测的响应时间,广泛应用于工业控制、汽车电子和物联网设备等对实时性要求高的场景。当低优先级任务执行**长时间非阻塞运算**且无中断发生时,调度器无法被触发,导致高优先级任务虽处于就绪态却无法获得CPU,造成系统响应延迟。理解**任务状态机**与调度点,是优化实时性、避免此 阅读详情
多线程进阶==>juc并发编程
1、什么是juc?

**java.util.concurrent *** java.util工具包

业务:普通的线程代码 Thread

Runnable 没有返回值,效率比Callable相抵较低!

2、线程和进程

进程:一个程序 ,QQ.exe 程序的集合;

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

java默认包含几个线程?2个 main、GC

线程:开了一个进程typora,写字,自动保存(线程负责)

对于java而言:Thread、Runnable、Callable

java真的可以开启线程么?

/**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

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

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

并发、并行

并发编程:并发、并行

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

  • CPU一核,模拟出来多条线程,天下武功,为快不破,快速交替

并行:(多个人一起行走)

  • CPU多核,多个线程可以同时执行
package cn.smallcosmos;

/**
 * @Date 2020/7/2 上午11:39
 * @Created by zhaoli
 */
public class Demo1 {
    public static void main(String[] args) {
      //获取CPU核心数 
      //CPU密集型,IO密集型
     System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

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

线程有几个状态 --> 6个

public enum State {
        //新生
        NEW,

        //运行
        RUNNABLE,

        //阻塞
        BLOCKED,

        //等待
        WAITING,

        //超时等待
        TIMED_WAITING,

        //终止
        TERMINATED;
    }

wait/sleep的区别

1、来自不同的类

wait–>Object

sleep–>Thread

2、关于锁的释放

wait–>会释放锁

sleep–> 不会释放锁

3、使用的范围不同

wait–>必须在同步控制块中使用

sleep–>可以在任何地方睡

4、是否需要捕获异常

wait–>不需要捕获异常

sleep–>必须捕获异常

3、lock锁(重点)

传统Synchronized

Lock 接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hQBN1DI1-1596633696952)(/tmp/1594112325562.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KsFfquUo-1596633696955)(/tmp/1594113447324.png)]

公平锁

非公平锁(java默认)

package cn.smallcosmos;

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

/**
 * @Date 2020/7/7 下午4:34
 * @Created by zhaoli
 */
public class SaleTicketDemo2 {
    public static void main(String[] args) {
        Ticket2 ticket = new Ticket2();
        new Thread(() -> {
            while(true)
                ticket.sale();
        },"A").start();

        new Thread(() -> {
            while(true)
                ticket.sale();
        },"B").start();

        new Thread(() -> {
            while(true)
                ticket.sale();
        },"C").start();

    }


}

class Ticket2 {
    private int nums = 30;

    Lock lock = new ReentrantLock();
    public void sale(){

        lock.lock();//加锁
        try {
            if(nums > 0){
                System.out.println(Thread.currentThread().getName() + "正在卖第" + nums -- + "票" + "," + "剩余" + nums + "票");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

synchronized和Lock区别

1、synchnorized 内置java关键字,Lock是一个java类。

2、synchnorized 无法判断锁的状态,Lock可以判断是否获取到了锁。

3、synchnorized会自动释放锁,Lock必须手动释放锁,如果不释放锁,会发生死锁。

4、synchnorized 线程1(获得锁,阻塞) 线程2(等待);Lock锁就不一定会等待 。

5、synchnorized 可重入锁,不可以中断,非公平;Lock,可重入锁,可以判断锁,非公平(可以自己设置)。

6、synchnorized 适合锁少量的代码同步问题,Lock适合大量的同步代码。

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

4、生产者和消费者

生产者和消费者 synchnorized 版本

package cn.smallcosmos.pc;

/**
 * @Date 2020/7/7 下午5:56
 * @Created by zhaoli
 */
public class TestDemo1 {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    data.increment();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

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

class Data {
    private int data;

    //+1  生产者
    public synchronized void increment() throws InterruptedException {
        if (data != 0) {
            this.wait();
        }
        data++;
        System.out.println(Thread.currentThread().getName() + "->" + data);
        notifyAll();
    }

    //-1 消费者
    public synchronized void decrement() throws InterruptedException {
        if (data == 0) {
            this.wait();
        }
        data--;
        System.out.println(Thread.currentThread().getName() + "->" + data);
        notifyAll();
    }
}na	

使用if判断会产生虚假唤醒问题,解决办法将if改为while。

虚假唤醒结果分析

​ 可以看到上述结果出现了data为2的情况,不符合之前的预期,出现问题的场景是这样的:当data为1的时候,线程A和B先后获取锁去生产数据的时候会被阻塞住,然后消费者C或者D消费掉数据后去notifyAll()唤醒了线程A和B,被唤醒的A和B没有再次去判断data状态,就去执行后续增加数据的逻辑了,导致两个生产者都执行了increment(),最终data出现了2这种情况。也就是说线程A和B有一个是不应该被唤醒的却被唤醒了,出现这个问题的关键点在于程序中使用到了if判断,只判断了一次data的状态,应该使用while循环去判断

生产者和消费者JUC版本

package cn.smallcosmos.pc;

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

/**
 * @Date 2020/7/8 上午9:20
 * @Created by zhaoli
 */
public class TestDemo2 {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    data.increment();
                }

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

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "C").start();

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

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


    }
}

class Data2 {
    private int data;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    //+1  生产者
    public  void increment() throws InterruptedException {
        lock.lock();//加锁
        try {
            while (data != 0) {
                condition.await();//等待
            }
            data++;
            System.out.println(Thread.currentThread().getName() + "->" + data);
            condition.signalAll();//唤醒所有
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();//解锁
        }
    }

    //-1 消费者
    public  void decrement() throws InterruptedException {
        lock.lock();
        try {
            while (data == 0) {
                condition.await();
            }
            data--;
            System.out.println(Thread.currentThread().getName() + "->" + data);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

condition精准的通知和唤醒线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1o3J6Sor-1596633696956)(/tmp/1594174231607.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jj5rQUex-1596633696958)(/tmp/1594175143223.png)]

代码测试:

package cn.smallcosmos.pc;

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

/**
 * @Date 2020/7/8 上午10:29
 * @Created by zhaoli
 * 执行顺序 ABC
 */
public class TestDemo3 {
    public static void main(String[] args) {
        data3 data = new data3();
        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 data3 {
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int number = 1;

    public void printA(){
        lock.lock();
        try {
            while(number != 1){
                condition1.await();
            }
            number = 2;
            System.out.println(Thread.currentThread().getName() + " = " + number);
            //唤醒指定的人 B
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printB(){
        lock.lock();
        try {
            while(number != 2){
                condition2.await();
            }
            number = 3;
            System.out.println(Thread.currentThread().getName() + " = " + number);
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printC(){
        lock.lock();
        try {
            while(number != 3){
                condition3.await();
            }
            number = 1;
            System.out.println(Thread.currentThread().getName() + " = " + number);
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
5、8锁现象

如何判断锁的是谁?

package cn.smallcosmos.demo2;

import java.util.concurrent.TimeUnit;

/**
 * @Date 2020/7/8 上午11:02
 * @Created by zhaoli
 * 8锁问题,实际上是关于锁的8个问题
 * 1、标准情况下,两线程是先打印发短信还是打电话? 发短信  打电话`
 * 2、sendMsg延迟四秒,两线程是先打印发短信还是打电话? 发短信  打电话`
 */
public class TestDemo1 {

    public static void main(String[] args) {
        phone phone = new phone();
        new Thread(() -> {
            phone.sendMsg();
        },"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 sendMsg(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("发短信");
    }

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

import java.util.concurrent.TimeUnit;

/**
 * @Date 2020/7/9 上午9:11
 * @Created by zhaoli
 * 3、   一个加锁的方法和一个普通方法 ,两线程是先打印发短信还是打电话? hello 发短信`
 * 4、 两个对象两个同步方法,两线程是先打印发短信还是打电话? 打电话 发短信`
 *
 */
public class TestDemo2{

    public static void main(String[] args) {
        phone2 phone = new phone2();
//        phone2 phone1 = new phone2();
        new Thread(() -> {
            phone.sendMsg();
        },"A").start();

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

        new Thread(() -> {
            phone.call();
        },"B").start();
    }
}
class phone2 {
    //synchronized 锁的对象是方法的调用者
    //两个方法使用的是同一个锁(phone)
    //static 静态方法
    //类一加载就有了,锁的是class模板
    public static synchronized void sendMsg(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("发短信");
    }

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

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

package cn.smallcosmos.demo2;

import java.util.concurrent.TimeUnit;

/**
 * @Date 2020/7/9 上午9:32
 * @Created by zhaoli
 *  5、  两个静态加锁方法,两线程是先打印发短信还是打电话? 发短信  打电话`
 *  6、  两个对象,两个静态加锁方法,两线程是先打印发短信还是打电话? 发短信  打电话`
 */ 
public class TestDemo3{

    public static void main(String[] args) {
        phone3 phone = new phone3();
        phone3 phone1 = new phone3();
        new Thread(() -> {
            phone.sendMsg();
        },"A").start();

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

        new Thread(() -> {
            phone1.call();
        },"B").start();
    }
}
class phone3 {
    //synchronized 锁的对象是方法的调用者
    //两个方法使用的是同一个锁(phone)
    public static synchronized void sendMsg(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("发短信");
    }

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

    public void hello(){
        System.out.println("hello");
    }
}
package cn.smallcosmos.demo2;

import java.util.concurrent.TimeUnit;

/**
 * @Date 2020/7/9 上午9:32
 * @Created by zhaoli
 * 7、一个对象,一个静态同步方法一个非静态同步方法,两线程是先打印发短信还是打电话?  打电话 发短信 `
 * 8、两个对象,一个静态同步方法一个非静态同步方法,两线程是先打印发短信还是打电话?  打电话 发短信 `
 */
public class TestDemo4{

    public static void main(String[] args) {
        phone4 phone = new phone4();
        phone4 phone1 = new phone4();
        new Thread(() -> {
            phone.sendMsg();
        },"A").start();

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

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

class phone4 {
    //synchronized 锁的对象是方法的调用者
    //两个方法使用的是同一个锁(phone)
    public static synchronized void sendMsg(){
        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");
    }
}

小结

new this 锁的是对象

static class 锁的是类模板

6、集合类不安全

list不安全

package cn.smallcosmos.unsafe;

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

/**
 * @Date 2020/7/9 上午9:58
 * @Created by zhaoli
 * java.util.ConcurrentModificationException  并发修改异常保证可见性
 *
 */
public class TestList {
    public static void main(String[] args) {

        /**
         * 解决方案
         * 1、List<String> list = new Vector<>();不推荐
         * 2、List<String> list = Collections.synchronizedList(new ArrayList<>());
         * 3、List<String> list = new CopyOnWriteArrayList<>();
         *
         */
//        List<String> list = new ArrayList();
//        List<String> list = new Vector<>();
//        List<String> list = Collections.synchronizedList(new ArrayList<>());
        //CopyOnWrite  写入时复制      COW      计算机程序设计领域的一种优化策略
        //多个线程调用的时候,list,先复制原数组,创建一个新数组,插入数据后,再将新数组写入原数组
        //在写入是避免覆盖,造成数据问题。
        List<String> list = new 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不安全

package cn.smallcosmos.unsafe;

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

/**
 * @Date 2020/7/9 上午11:36
 * @Created by zhaoli
 * java.util.ConcurrentModificationException 并发修改异常
 */
public class TestSet {
    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 = 0; i < 30; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }
}

7、Callable

new Thread(Runnable) 参数必须为Runnable

FutureTask实现了Runnable接口

FutureTask(Callable callable)` 创建一个FutureTask,他将在运行时执行指定的Callable。

测试代码:

package cn.smallcosmos.callable;

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

public class TestCallable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable myCallable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        new Thread(futureTask).start();
        System.out.println(futureTask.get());
    }
}
class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("调用callable()");
        return 1024;
    }
}
8、其他辅助类

CountDownLatch(减法计数器)

package cn.smallcosmos.countdownlatch;

import java.util.concurrent.CountDownLatch;

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

        for (int i = 1; i <= 7; i++) {
            int temp = i;
            new Thread(() -> {
                System.out.println("第" + temp + "人出门了");
                countDownLatch.countDown();
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
        System.out.println("CLose Door");
    }
}

CyclicBarrier(加法计数器) 循环栅栏

package cn.smallcosmos.cyclicbarrier;

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

public class TestCyclicbarrier {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, new Runnable() {
            public void run() {
                System.out.println("集齐7颗龙珠,召唤神龙!!!");
            }
        });
        for (int i = 1; i <= 7; i++) {
            final int temp = i;
            new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + "正在集齐第" + temp + "颗龙珠");
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    },String.valueOf(i)).start();
}
    }

}

Semaphore(信号量)

package cn.smallcosmos.semaphore;

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

public class TestSemphore {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);//创建一个资源数量为3的信号量
        for (int i = 1; i <= 6; i++) {

            new Thread(() -> {
                try {
                    semaphore.acquire();//获取一个资源,如果资源数目为0,则等待释放,
                    System.out.println(Thread.currentThread().getName() + "抢到了车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "离开了车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();//释放资源,资源数目+1
                }


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

9、读写锁

ReadWriteLock

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1cZk00lN-1596633696960)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200725201455899.png)]


package cn.smallcosmos.rw;

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

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

        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.get(temp + "");
            },String.valueOf(i)).start();
        }
    }
}

//加锁
class MyCacheLock {
    private volatile Map<String,Object> map = new HashMap<>();
//    读写锁
    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    //存
    public void setKey(String key,Object value){
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "写入" + value);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName() + "写入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

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


class MyCache {
    private volatile Map<String,Object> map = new HashMap<>();

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

    //取
    public void get(String key){
        System.out.println(Thread.currentThread().getName() + "读取" + map.get(key));
        System.out.println(Thread.currentThread().getName() + "读取OK" );
    }
}
10、阻塞队列

​ BlockingQueue

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kvfube0X-1596633696961)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200725204231292.png)]

四组API

方式抛出异常有返回值阻塞等待超时等待
添加add()offer()put()offer()有参
移除remove()poll()take()poll()有参
判断队列首部element()peek()--
 /**
     * 抛出异常
     * */
    public static void test1(){
        ArrayBlockingQueue bq = new ArrayBlockingQueue<>(3);
        System.out.println(bq.add("a"));
        System.out.println(bq.add("b"));
        System.out.println(bq.add("c"));

        //java.lang.IllegalStateException: Queue full
        //System.out.println(bq.add("d"));
        System.out.println(bq.remove());
        System.out.println(bq.remove());
        System.out.println(bq.remove());

        //java.util.NoSuchElementException
        //System.out.println(bq.remove());

    }
 /**
     * 有返回值,没有异常
     */
    public static void test2(){
        ArrayBlockingQueue<Object> 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")); //返回false,不抛出异常

        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()); //返回null,不抛出异常
    }
  /**
     *阻塞等待
     */

    public static void test3() throws InterruptedException {
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
//        blockingQueue.put("d");  //程序会阻塞到这个地方,直到这个元素放进去
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());//程序会阻塞到这个地方,直到可以取出来一个元素
    }
 /**
     * 超时等待
     * @throws InterruptedException
     */
    public static void test4() throws InterruptedException {
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        //System.out.println(blockingQueue.offer("d",2, TimeUnit.SECONDS)); //等待超过两秒,程序就会结束



        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS));
    }

SynchronousQueue(同步队列)

SynchronousQueue这种队列的特点是不缓存数据,而是缓存线程,线程分为生产者线程和消费者线程,一个生产者线程和一个消费者线程是互补的,当一个生产者线程遇到一个消费者线程的时候就会直接进行数据交换,所以这种队列的技术点比较高,理解起来难度较大。一个线程只能缓存一个数据,当一个线程插入数据之后就会被阻塞,直到另外一个线程消费了其中的数据。

package cn.smallcosmos.bq;

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

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

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dl9kRD1c-1596633696962)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200727204222653.png)]

11、线程池(重点)

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

池化技术

程序运行的本质==》占用系统资源 优化资源的使用==》池化技术

池化技术:事先准备一些资源,需要使用来池子里拿,用完归还到池子,减少了资源创建和销毁的消耗,从而提高资源利用。

线程池的好处

1、降低资源消耗

2、提高响应速度

3、方便管理

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

三大方法

package cn.smallcosmos.pool;

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

public class TestExecutors {
    public static void main(String[] args) {
//        ExecutorService threadpool = Executors.newSingleThreadExecutor();//单个线程

//        ExecutorService threadpool = Executors.newFixedThreadPool(5);//固定大小的线程池
        ExecutorService threadpool = Executors.newCachedThreadPool();//可伸缩,依赖于电脑性能
        for (int i = 0; i < 100; i++) {
            threadpool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "ok");
            });

        }
        threadpool.shutdown();
    }
}

七大参数

源码分析

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

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

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    } 
//本质:ThreadPoolExecutor
 public ThreadPoolExecutor(int corePoolSize,//核心线程数
                              int maximumPoolSize,//最大线程数
                              long keepAliveTime,//存活时间
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//阻塞队列
                              ThreadFactory threadFactory,//线程工厂
                              RejectedExecutionHandler handler//拒绝策略) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OjwzxN5U-1596633696963)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200727213634178.png)]

手动创建一个线程池

四种拒绝策略

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NFhZLf7G-1596633696964)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200727225243220.png)]

package cn.smallcosmos.pool;

        import java.util.concurrent.*;

/**
 * ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
 * ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
 * ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
 * ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
 */
public class TestExecutors {
    public static void main(String[] args) {
        ExecutorService threadpool = new ThreadPoolExecutor(
                2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy()
        );
        //最大承载量:Queue + max
        for (int i = 1; i <= 9; i++) {
            threadpool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "ok");
            });

        }
        threadpool.shutdown();
    }
}

了解和拓展

如何设置线程池的最大大小

//获取电脑CPU总核心数 
Runtime.getRuntime().availableProcessors()

IO密集型

这类任务的CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。常见的大部分任务都是IO密集型任务,比如Web应用。对于IO密集型任务,任务越多,CPU效率越高(但也有限度)。

一般配置线程数=CPU总核心数 * 2 +1

CPU密集型

要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。

一般配置线程数=CPU总核心数+1(+1是为了利用等待空闲)

12、四大函数式接口(必须掌握)

lambda表达式、链式编程、函数式接口、stream流式计算

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

@FunctionalInterface //函数式接口
public interface Runnable {
    void run();
}

代码测试

函数型接口

package cn.smallcosmos.function;

import java.util.function.Function;

/**
 * Function函数型接口,有一个输入参数,有一个输出
 * 只要是函数型接口就可以用lambda表达式简化
 */
public class Demo01 {
    public static void main(String[] args) {
//        Function function = new Function<String,String>() {
//            @Override
//            public String apply(String s) {
//                return s;
//            }
//        };
        Function function = (str) -> {return str;};
                System.out.println(function.apply("aaa"));
    }

}

断定型接口

package cn.smallcosmos.function;

import java.util.function.Predicate;

/**
 * 断定型接口 : 只有一个输入参数,并且返回值只能是boolean类型
 */
public class Demo2 {
    public static void main(String[] args) {
//        Predicate<String> predicate = new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                return s.isEmpty();
//            }
//        };
        Predicate<String> predicate = (str) -> {return str.isEmpty();};
                System.out.println(predicate.test("aaa"));
    }
}

消费型接口

package cn.smallcosmos.function;

import java.util.function.Consumer;

/**
 * 消费型接口:只有一个输入参数,没有返回值
 */
public class Demo03 {
    public static void main(String[] args) {
//        Consumer consumer = new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        };
        Consumer consumer = (str) -> { System.out.println(str);};
                consumer.accept("aaa");
    }
}

供给型接口

package cn.smallcosmos.function;

import java.util.function.Supplier;

/**
 * 供给型接口:没有输入参数,有一个返回值
 */
public class Demo04 {
    public static void main(String[] args) {
//        Supplier<Integer> supplier = new Supplier<Integer>() {
//            @Override
//            public Integer get() {
//                return 1024;
//            }
//        };
        Supplier<Integer> supplier = () -> {return 1024;};
                System.out.println(supplier.get());
    }
}

Stream流式计算

什么是Stream流式计算

大数据:存储加计算

集合,MySQL本质就是存储东西的‘

计算交给流来操作

package cn.smallcosmos.function;

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

/**
 * 1、ID必须是偶数
 * 2、年龄必须大于23岁
 * 3、用户名转为大写
 * 4、用户名字母倒着排序
 * 5、只输出一个用户
 */
public class Test {

    public static void main(String[] args) {
        Student u1 = new Student(1,20,"a");
        Student u2 = new Student(2,21,"b");
        Student u3 = new Student(3,22,"c");
        Student u4 = new Student(4,24,"d");
        Student u5 = new Student(6,25,"e");

        List<Student> students = Arrays.asList(u1, u2, u3, u4, u5);
        students.stream()
                .filter((u) ->{return u.getId() % 2 == 0;})
                .filter((u) -> {return  u.getAge() > 23;})
                .map((u) -> {return u.getName().toUpperCase();})
                .sorted((uu1,uu2) -> {return uu2.compareTo(uu1);})
                .limit(1)
                .forEach(System.out::println);
    }
}

13、ForkJoin(分支合并)

什么是ForkJoin

ForkJoin在JDK1.7之后出现,并行执行任务,提高效率,大数据量

大数据:Map Reduce(把大任务拆分为小任务)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4jTMQdLu-1596633696965)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200730204451908.png)]

ForkJoin特点:工作窃取

这里面操作的都是双端队列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a1s2IXBr-1596633696966)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200730205010180.png)]

package cn.smallcosmos.function;

import java.util.concurrent.RecursiveTask;

public class ForkJoinDemo  extends RecursiveTask<Long> {
    private  long start;
    private long end;
    private long temp = 10000L;

    public ForkJoinDemo() {

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

    }

    @Override
    protected Long compute() {
        long sum = 0;
        if(end - start < temp){
            for(long i = start;i <= end;i++){
                sum += i;
            }
            return sum;
        }else{
            long mid = (start + end) / 2;
            //将任务拆分为两部分
            ForkJoinDemo task1 = new ForkJoinDemo(start, mid);
            task1.fork();
            ForkJoinDemo task2 = new ForkJoinDemo(mid  + 1, end);
            task2.fork();
            //合并结果
           return task1.join() + task2.join();
        }
    }
}
//测试代码
package cn.smallcosmos.function;

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

public class TestForkJoin {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //10_0000_0000     100_0000_0000
        test1();//392     8025
//        test2(); //346  3190
//        test3();//352   2048
    }
    //普通方法
    public static void test1(){
        long start = System.currentTimeMillis();
        long sum = 0L;
        for(long i = 0L;i <= 100_0000_0000L;i++){
            sum += i;
        }
        long end = System.currentTimeMillis();
        System.out.println("sum = " + sum + "时间:" + (end - start));
    }
    //使用ForkJoin
    public static void test2() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> submit = forkJoinPool.submit(new ForkJoinDemo(0L, 100_0000_0000L));
        Long sum = submit.get(); long end = System.currentTimeMillis();
        System.out.println("sum = " + sum + "时间:" + (end - start));
    }
    //Stream流式计算
    public static void test3() {
        long start = System.currentTimeMillis();
        long sum = LongStream.rangeClosed(0L, 100_0000_0000L).parallel().reduce(0, Long::sum);
        long end = System.currentTimeMillis();
        System.out.println("sum = " + sum + "时间:" + (end - start));
    }

}

14、异步回调

Future 对将来某个事件结果进行建模

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pSpsVRZI-1596633696967)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200802102108070.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lhT7F315-1596633696968)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200802172107872.png)]

代码测试

package cn.smallcosmos.future;

import java.util.concurrent.CompletableFuture;

public class Demo01 {

    public static void main(String[] args) throws Exception {
        // 创建异步执行任务:
        CompletableFuture<Double> cf = CompletableFuture.supplyAsync(Demo01::fetchPrice);
        // 如果执行成功:
        cf.thenAccept((result) -> {
            System.out.println("price: " + result);
        });
        // 如果执行异常:
        cf.exceptionally((e) -> {
            e.printStackTrace();
            return null;
        });
        System.out.println("111111");
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(20000);
    }

    static Double fetchPrice() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        }
        if (Math.random() < 0.3) {
            throw new RuntimeException("fetch price failed!");
        }
        return 5 + Math.random() * 20;
    }
}

执行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HfPOFcgD-1596633696969)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200802170623832.png)]

可见CompletableFuture的优点是:

  • 异步任务结束时,会自动回调某个对象的方法;
  • 异步任务出错时,会自动回调某个对象的方法;
  • 主线程设置好回调后,不再关心异步任务的执行。

如果只是实现了异步回调机制,我们还看不出CompletableFuture相比Future的优势。CompletableFuture更强大的功能是,多个CompletableFuture可以串行执行,例如,定义两个CompletableFuture,第一个CompletableFuture根据证券名称查询证券代码,第二个CompletableFuture根据证券代码查询证券价格,这两个CompletableFuture实现串行操作如下:

public class Main {
    public static void main(String[] args) throws Exception {
        // 第一个任务:
        CompletableFuture<String> cfQuery = CompletableFuture.supplyAsync(() -> {
            return queryCode("中国石油");
        });
        // cfQuery成功后继续执行下一个任务:
        CompletableFuture<Double> cfFetch = cfQuery.thenApplyAsync((code) -> {
            return fetchPrice(code);
        });
        // cfFetch成功后打印结果:
        cfFetch.thenAccept((result) -> {
            System.out.println("price: " + result);
        });
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(2000);
    }

    static String queryCode(String name) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
        return "601857";
    }

    static Double fetchPrice(String code) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
        return 5 + Math.random() * 20;
    }
}

除了串行执行外,多个CompletableFuture还可以并行执行。例如,我们考虑这样的场景:

同时从新浪和网易查询证券代码,只要任意一个返回结果,就进行下一步查询价格,查询价格也同时从新浪和网易查询,只要任意一个返回结果,就完成操作:

public class Main {
    public static void main(String[] args) throws Exception {
        // 两个CompletableFuture执行异步查询:
        CompletableFuture<String> cfQueryFromSina = CompletableFuture.supplyAsync(() -> {
            return queryCode("中国石油", "https://finance.sina.com.cn/code/");
        });
        CompletableFuture<String> cfQueryFrom163 = CompletableFuture.supplyAsync(() -> {
            return queryCode("中国石油", "https://money.163.com/code/");
        });

        // 用anyOf合并为一个新的CompletableFuture:
        CompletableFuture<Object> cfQuery = CompletableFuture.anyOf(cfQueryFromSina, cfQueryFrom163);

        // 两个CompletableFuture执行异步查询:
        CompletableFuture<Double> cfFetchFromSina = cfQuery.thenApplyAsync((code) -> {
            return fetchPrice((String) code, "https://finance.sina.com.cn/price/");
        });
        CompletableFuture<Double> cfFetchFrom163 = cfQuery.thenApplyAsync((code) -> {
            return fetchPrice((String) code, "https://money.163.com/price/");
        });

        // 用anyOf合并为一个新的CompletableFuture:
        CompletableFuture<Object> cfFetch = CompletableFuture.anyOf(cfFetchFromSina, cfFetchFrom163);

        // 最终结果:
        cfFetch.thenAccept((result) -> {
            System.out.println("price: " + result);
        });
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(200);
    }

    static String queryCode(String name, String url) {
        System.out.println("query code from " + url + "...");
        try {
            Thread.sleep((long) (Math.random() * 100));
        } catch (InterruptedException e) {
        }
        return "601857";
    }

    static Double fetchPrice(String code, String url) {
        System.out.println("query price from " + url + "...");
        try {
            Thread.sleep((long) (Math.random() * 100));
        } catch (InterruptedException e) {
        }
        return 5 + Math.random() * 20;
    }
}	

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lQYk4dFn-1596633696969)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200802172418198.png)]

除了anyOf()可以实现“任意个CompletableFuture只要一个成功”,allOf()可以实现“所有CompletableFuture都必须成功”,这些组合操作可以实现非常复杂的异步流程控制。最后我们注意CompletableFuture的命名规则:

  • xxx():表示该方法将继续在已有的线程中执行;

  • xxxAsync():表示将异步在线程池中执行。

CompletableFuture可以指定异步处理流程:

  • thenAccept()处理正常结果;
  • exceptional()处理异常结果;
  • thenApplyAsync()用于串行化另一个CompletableFuture;
  • anyOf()和allOf()用于并行化多个CompletableFuture。
15、JMM

请你谈谈对对volatile的理解

volatile是jvm提供的轻量级的同步机制。

1、保证可见性

2、不保证原子性

3、防止指令重排

什么是JMM

JMM java内存模型,不存在的东西,概念!约定!

关于JMM一些同步的约定

1、线程解锁前,必须吧共享变量立刻刷回主存。

2、线程加锁前,必须把主存中的最新值读到工作内存中去。

3、加锁和解锁是同一把锁。

线程 工作内存 主内存

8种操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ifsFJkc-1596633696970)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200802182117778.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fg4qpOO9-1596633696971)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200802182400525.png)]

内存交互操作有8种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类型的变量来说,load、store、read和write操作在某些平台上允许例外)

    • lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态
    • unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
    • read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用
    • load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中
    • use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令
    • assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中
    • store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用
    • write  (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中

JMM对这八种指令的使用,制定了如下规则:

    • 不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write
    • 不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存
    • 不允许一个线程将没有assign的数据从工作内存同步回主内存
    • 一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量实施use、store操作之前,必须经过assign和load操作
    • 一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解锁
    • 如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值
    • 如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量
    • 对一个变量进行unlock操作之前,必须把此变量同步回主内存

问题:线程不知道主内存中的值发生了变化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g19DPUC2-1596633696972)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200802183802282.png)]

16、Volatile

保证可见性

package cn.smallcosmos.volatile1;

import java.util.concurrent.TimeUnit;

public class TestJMM {
    static volatile int num = 0;
    public static void main(String[] args) throws InterruptedException {

        new Thread(() -> { //如果不加volatile,线程1对于主内存中的num变化感知不到,会造成死循环,程序无法结束
            while(num == 0){

            }
        }).start();
        TimeUnit.SECONDS.sleep(3);
        num = 1;
        System.out.println(num);
    }
}

不保证原子性

原子性:不可分割

package cn.smallcosmos.volatile1;

public class TestJMM02 {
	//volatile不保证原子性
    private volatile static int num = 0;
    public  static void  add(){
        num++; //不是原子性操作
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 2000; j++) {
                    add();
                }
            }).start();
        }

        while(Thread.activeCount() > 2){ //main GC
            Thread.yield();
        }

        System.out.println(num);
    }
}

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SiXsRJRW-1596633696973)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200802190303693.png)]

字节码文件(javap -c TestJMM02)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ipyN6hdf-1596633696974)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200802190058234.png)]

原子类:使用原子类解决原子性问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IwP2lUoZ-1596633696975)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200803202029125.png)]

package cn.smallcosmos.volatile1;

import java.util.concurrent.atomic.AtomicInteger;

public class TestJMM02 {
    private  static AtomicInteger num = new AtomicInteger();
    public  static void  add(){
       // num++; //不是原子性操作
        num.getAndIncrement();
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 2000; j++) {
                    add();
                }
            }).start();
        }

        while(Thread.activeCount() > 2){ //main GC
            Thread.yield();
        }

        System.out.println(num);
    }
}

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-abLFtEfh-1596633696976)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200803202835338.png)]

这些类的底层都是和操作系统挂钩!在内存中修改值!unsafe类是一个很特殊的存在

什么是指令重排

你写的程序,计算机并不是按照你写的那样执行的。

源代码 --》编译器优化的重排–》指令并行也可能会重排–》内存系统也会重排–》执行

计算机在进行指令重排是考虑:数据间的依赖性

int x = 1;//1
int y = 2;//2
x = x + 1;//3
y = x * x;//4
我们所期望的执行顺序 1234  ,但是可能执行的顺序是 1324  2134
    可不可能是4123!

可能造成影响的结果 ab xy 初始值都是0

线程A线程B
x = ay = b
b = 1a = 2
线程A线程B
b = 1a = 2
x = ay = b

期望的结果x = 0;y = 0;

指令重排可能会造成的结果:x = 2;y = 1;

volatile 可以避免指令重排

内存屏障。CPU指令。作用:

1、保证特定的操作的执行顺序

可以保证某些变量的内存可见性(利用这些特性volatile实现了可见性)

17、彻底玩转单例模式

饿汉式、DCL懒汉式,深究!

饿汉式

package cn.smallcosmos.singleton;
//饿汉式单例模式
public class Demo01 {
    private Demo01(){
        System.out.println(Thread.currentThread().getName());
    }

    //在类加载的时候进行初始化,可能会浪费内存空间
    private final  static Demo01 demo01 = new Demo01();

    public static Demo01 getDemo01(){
        return demo01;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Demo01.getDemo01();
            }).start();
        }
    }
}

懒汉式

package cn.smallcosmos.singleton;

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

//懒汉式单例模式
public class Demo02 {
    private static boolean zzl = false;
    private Demo02(){
//        System.out.println(Thread.currentThread().getName());
//        synchronized (Demo02.class){
//            if(demo02 != null){
//                throw new RuntimeException("不要试图通过反射来进行破坏");
//            }
//        }
        if(zzl == false){
            zzl = true;
        }else{
            throw new RuntimeException("不要试图通过反射来进行破坏");
        }
    }

    private  volatile  static Demo02 demo02 = null;

    //双重检验锁模式的懒汉单例模式

    /**
     * 1、分配内存空间
     * 2、执行构造方法,实例化对象
     * 3、把这个引用指向这个空间
     *
     *
     * 期望执行顺序  123
     * 可能执行顺序  132 A
     *                 B  在A还没完成构造的时候,这时候B判断当前实例不为空,造成问题;
     *	使用volatile禁止指令重排来解决。
     */
    public static Demo02 getDemo02(){
        if(demo02 == null){
            synchronized (Demo02.class){
                if(demo02 == null){
                    demo02 = new Demo02();//不是一个原子性操作
                }
            }
        }
        return demo02;
    }
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//        for (int i = 0; i < 10; i++) {
//
//            new Thread(() -> {
//               Demo02.getDemo02();
//            }).start();
//        }

//        Demo02 demo02 = Demo02.getDemo02();
//        System.out.println(demo02);
        //使用反射暴力破解单例模式
        Field zzl = Demo02.class.getDeclaredField("zzl");
        zzl.setAccessible(true);
        Constructor<Demo02> constructor = Demo02.class.getDeclaredConstructor(null);
        constructor.setAccessible(true);
        Demo02 instance = constructor.newInstance();
        zzl.set(instance,false);
        Demo02 instance2 = constructor.newInstance();
        System.out.println(instance);
        System.out.println(instance2);
    }
}

枚举实现单例模式

package cn.smallcosmos.singleton;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//枚举实现单例模式
//枚举是不能被反射的,所以枚举才是实现单例模式的最佳方式
public enum EnumSingleton {
    SINGLETON;

    public static  EnumSingleton getInstance(){
        return SINGLETON;
    }
}

class test{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        EnumSingleton instance = EnumSingleton.SINGLETON;
//        EnumSingleton instance2 = EnumSingleton.SINGLETON;
        System.out.println(instance);
//        System.out.println(instance2);

        /**
         * 报错java.lang.NoSuchMethodException: cn.smallcosmos.singleton.EnumSingleton.<init>()
         * 通过反编译可以看到枚举是没有空参构造方法的,有一个有参构造(String,int),IDEA和javap反编译欺骗了我们。
         */
//        Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor(null);

        /**
         * 报错java.lang.IllegalArgumentException: Cannot reflectively create enum objects
         * 这个才是我们希望看到的结果
         */
        Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        EnumSingleton instance1 = constructor.newInstance();
        System.out.println(instance1);
    }
}

javap 反编译结果(这个结果是不正确的)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pmJnVI8w-1596633696976)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200803222613302.png)]

通过jad反编译得到的结果

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   EnumSingleton.java

package cn.smallcosmos.singleton;


public final class EnumSingleton extends Enum
{

    public static EnumSingleton[] values()
    {
        return (EnumSingleton[])$VALUES.clone();
    }

    public static EnumSingleton valueOf(String name)
    {
        return (EnumSingleton)Enum.valueOf(cn/smallcosmos/singleton/EnumSingleton, name);
    }

    private EnumSingleton(String s, int i)
    {
        super(s, i);
    }

    public static EnumSingleton getInstance()
    {
        return SINGLETON;
    }

    public static final EnumSingleton SINGLETON;
    private static final EnumSingleton $VALUES[];

    static 
    {
        SINGLETON = new EnumSingleton("SINGLETON", 0);
        $VALUES = (new EnumSingleton[] {
            SINGLETON
        });
    }
}

18、深入理解CAS

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ut3cSwVw-1596633696977)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200804202300183.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Baf4jVWZ-1596633696978)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200804202320439.png)]

ABA问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QHf8EPZS-1596633696979)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200804202358297.png)]

19、原子引用(解决ABA问题)
20、各种锁

公平锁 非公平锁

公平锁:非常公平,先来后到

非公平锁:非常不公平,可以插队(默认都是非公平锁)

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

可重入锁

可重入锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JmKF5EyE-1596633696980)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200804211831917.png)]

自旋锁

package cn.smallcosmos.lock;

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

//自定义自旋锁
public class SpinLockDemo {
    private Thread  thread = Thread.currentThread();
    private AtomicReference<Thread> atomicReference = new AtomicReference<>();
    //加锁
    public void myLock(){
        System.out.println(Thread.currentThread().getName()+"-->" + "myLock");
        while(!atomicReference.compareAndSet(null,thread)){

        }
    }

    //解锁

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


    public static void main(String[] args) throws InterruptedException {
        SpinLockDemo spinLockDemo = new SpinLockDemo();
        new Thread(() -> {
            spinLockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(3);
            }catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                spinLockDemo.myUnLock();
            }
        },"T1").start();

        TimeUnit.SECONDS.sleep(2);

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

死锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lttobSJc-1596633696981)(C:\Users\11915\AppData\Roaming\Typora\typora-user-images\image-20200805211751366.png)]

package cn.smallcosmos.lock;

import java.util.concurrent.TimeUnit;

public class DeadLock {
    public static void main(String[] args) {
        Resource resource = new Resource("lockA","lockB");
        new Thread(() -> {
            try {
                resource.add();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"T1").start();

        new Thread(() -> {
            resource.del();
        },"T2").start();



    }
}

class Resource{
    int a = 0;
    int b = 1;
    String lockA;
    String lockB;
    public Resource(String lockA,String lockB){
        this.lockA = lockA;
        this.lockB = lockB;
    }
    public void add() throws InterruptedException {
        synchronized (lockA){
            System.out.println(Thread.currentThread().getName() + "获取到" + lockA + "准备获取"+lockB);
            a++;
            System.out.println("a=" + a);
            TimeUnit.SECONDS.sleep(3); //保证在第一个线程还没有执行完第二个线程进入
            synchronized (lockB){
                b--;
                System.out.println("b=" + b);
            }
        }
    }

    public void del() {
        synchronized (lockB){
            System.out.println(Thread.currentThread().getName() + "获取到" + lockB + "准备获取"+lockA);
            b--;
            System.out.println("b=" + b);
            synchronized (lockA){
                a++;
                System.out.println("a=" + a);
            }
        }
    }
}

在获取多个锁的时候,不同线程获取多个不同对象的锁可能导致死锁。对于上述代码,线程T1和线程T2如果分别执行add()和dec()方法时:

  • 线程T1:进入add(),获得lockA;

  • 线程T2:进入dec(),获得lockB。

  • 线程T1:准备获得lockB,失败,等待中;

  • 线程T2:准备获得lockA,失败,等待中。

此时,两个线程各自持有不同的锁,然后各自试图获取对方手里的锁,造成了双方无限等待下去,这就是死锁。

死锁发生后,没有任何机制能解除死锁,只能强制结束JVM进程。

因此,在编写多线程应用时,要特别注意防止死锁。因为死锁一旦形成,就只能强制结束进程。

那么我们应该如何避免死锁呢?答案是:线程获取锁的顺序要一致。即严格按照先获取lockA,再获取lockB的顺序.

【图像去噪】论文精读:AKDT: Adaptive Kernel Dilation Transformer for Effective Image Denoising 论文题目:AKDT: Adaptive Kernel Dilation Transformer for Effective Image Denoising —— AKDT:用于有效图像去噪的自适应核膨胀Transformer图像去噪是一项基本但具有挑战性的任务,特别是在处理高分辨率图像和复杂的噪声模式时。大多数现有方法依赖于标准的 Transformer 架构,该架构通常计算复杂度高,并且对不同噪声水平的适应性有限。在本文中,我们介绍了自适应核膨胀Transformer(AKDT) 阅读详情

相关推荐

5G NR上行控制信道PUCCH

一、PUCCH概述 PUCCH用于承载上行控制信息,相比LTE,NR PUCCH支持5种不同的格式,按照时域上所占用的符号数量可以分为短格式和长格式两种,如下表所示,短格式占用1-2个符号,可以承载1-2bit信息,长格式占用4-14个符号,可承载大于2bit的信息。NR引入短格式PUCCH的目的是可以缩短HARQ-ACK反馈的时延,长格式仍然是考虑到持续时间长可以保证覆盖。 NR中,考虑到系...

一个关于5G NR的博客^^ 3万+

JUC 并发编程

主要对于juc的知识点总结

m0_53067943的博客 1476

STLink驱动安装全攻略:从卸载到Keil配置的完整避坑指南

本文提供了STLink驱动安装与Keil环境配置的完整避坑指南。详细讲解了从驱动卸载、重装到Keil调试器设置的每一步,并针对常见的设备无法识别、连接不稳定等问题给出了深度解决方案,帮助开发者快速搭建稳定的STM32开发环境。

weixin_29182481的博客 424

JUC(并发编程)

1.什么是JUC? JUC是指javaUtil包中的三个操作线程的包! 2.线程进程和程序 程序(Program):是一个静态的概念,一般对应于操作系统中的一个可执行的文件 ,比如:我们要启动酷狗听音乐,则对应酷狗可执行程序。当我们双击酷狗,则加载 程序到内存中,开始执行该程序,于是产生了"进程". 进程:执行中的程序叫做进程(Process),是一个动态的概念。现代的操作系统都可以同时启动多个进程。比如:我们在用酷狗听音乐,也可以使用wps写文档,也可以同时用浏览器查看网页。可以通过

abc98526的博客 1万+

temu登录接口逆向分析(含Py纯算)

【代码】temu登录接口逆向分析(含Py纯算)

数据精灵喵 1944

BSD盲区检测系统性能要求及试验方法

盲区监测系统BSD通过安装在车辆后方的两颗毫米波雷达实时监测驾驶员视野盲区,当发现视野盲区内出现其它道路使用者时,通过左右后视镜上的警示灯向驾驶员发出报警。

未知艺术家的博客 2356

【JUC】并发编程(全量整理)

CPU分时轮转调度机制:时间片即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的,即该进程允许运行的时间,使各个程序从表面上看是同时进行的。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。而不会造成CPU资源浪费。在宏观上:我们可以同时打开多个应用程序,每个程序并行不悖,同时运行。但在微观上:由于只有一个CPU,一次只能处理程序要求的一部分,如何处理公平,一种方法就是引入时间片,每个程序轮流执行。进程:内存中正在运行的

fearless的博客 1985

告别ROS1思维:在ROS2 Humble上,用Python搞定MoveIt2机械臂控制的完整流程

本文详细介绍了在ROS2 Humble环境下使用Python控制MoveIt2机械臂的完整流程。从环境配置、架构变革到实战操作,涵盖URDF适配、Action接口编程及性能优化技巧,帮助开发者高效迁移ROS1项目至ROS2平台,实现工业级机械臂控制。

weixin_30352645的博客 449

JUC并发编程

阻塞队列,顾名思义,首先它是一个队列, 通过一个共享的队列,可以使得数据由队列的一端输入,从另外一端输出;当队列是空的,从队列中获取元素的操作将会被阻塞。当队列是满的,从队列中添加元素的操作将会被阻塞。试图从空的队列中获取元素的线程将会被阻塞,直到其他线程往空的队列插入新的元素。试图向已满的队列中添加新元素的线程将会被阻塞,直到其他线程从队列中移除一个或多个元素或者完全清空,使队列变得空闲起来并后续新增。

qq_45767346的博客 641

定位教程7---旋转中心标定之方法二

手算相机相对机器人关系

Quintin 6230

【嘉立创EDA】从AD21导入pcb边界到嘉立创EDA专业版

有许多前期工程由AD进行完成,在后续update的过程中,由于开模等原因限制,部分pcb外型需要继续沿用,本文将此过程记录,以供有需要的读者参考。

l64481000的博客 4518

【并发编程】JUC并发编程(彻底搞懂JUC)

JUC实际上就是我们对于jdk中java.util .concurrent 工具包的简称,其结构如下:这个包下都是Java处理线程相关的类,自jdk1.5后出现。目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题!JUC主要是指JDK8中java.util.concurrent里提供的一系列线程并发工具,但是线程并发的问题远不止几个工具这么简单。要学习工具使用,更要能深入理解工具的原理以及处理线程并发问题的思路。

DreamSun的博客 7612

【CUDA Runtime】第一个“Hello World“程序

CUDA(Compute Unified Device Architecture)是 NVIDIA 提供的一个并行计算平台和编程模型,旨在通过利用 GPU 的强大计算能力来加速计算密集型应用。对于许多开发者而言,开始学习 CUDA 编程的第一步通常是编写一个简单的“Hello World”程序。尽管 CUDA 的实际应用远远超出一个简单的例子,但这个初步的示例能帮助开发者快速入门,理解基本的 CUDA 编程流程。

m0_62599305的博客 1505

Java并发编程(JUC)

1、Java并发编程——线程之间高效协作 2、了解JUC基本原理,了解各种锁的机制,避免死锁

weixin_43872993的博客 4357

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

【JAVA 进阶】重生之我要学会 JUC 并发编程

摘要 本文深入探讨Java并发工具包(JUC)的核心技术及应用。首先介绍并发编程的基本概念与挑战,包括并发与并行的区别、Java内存模型和happens-before原则。然后详细分析JUC包的整体架构,包括原子类、锁机制、并发容器和线程池等组件。重点解析CAS(Compare-And-Swap)机制原理及其在原子类中的应用,涵盖基本类型、数组、引用类型和字段更新器等原子类实现。文章还讨论了CAS的ABA问题及其解决方案,并展示如何利用AtomicStampedReference解决该问题。通过理论结合实践

CodeSuc 的技术博客 2101

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

JUC并发编程-高级篇

JUC并发编程-高级篇:1. JUC并发编程介绍、2. 线程基础知识

LiuYQi的博客 911

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

尚硅谷JUC并发编程课程笔记总结

JUC并发编程 1、什么是juc JUC是java.util.concurrent包的简称,在Java5.0添加,目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题! 2、线程基础知识复习 1把锁:synchronized(后面细讲) 2个并: 并发:(concurrent):是在同一实体上的多个事件,是在一台机器上“同时”处理多个任务,同一时刻,其实是只有一个事情再发生。 并行(parallel):是在不同实体上的多个事件,是在多台处理器上同时处理多个任务,

qq_59366033的博客 3018

【JUC并发编程】

JUC是Java Util Concurrent的缩写,是Java SE 5.0中新增的一个包,主要提供了在并发编程中使用的工具类和框架。JUC包含了许多用于多线程编程的工具类和接口,如锁、原子变量、线程池、阻塞队列等。这些工具类和接口可以帮助开发者更方便地进行多线程编程,从而提高程序的并发性能和可靠性。JUC包中的工具类和接口都是线程安全的,可以在多线程环境下安全地使用。它们的设计和实现都是基于并发编程的最佳实践和原则,可以有效地避免线程安全问题的发生。

蛋饼吧的博客 1824

并发编程——JUC知识脑图

摘要 并发编程在软件编程中尤为突出和重要,在当今面试或工作中也是不可缺少的。作为一名高级java开发工程师,并发编程的技能已经成为了重要的一项。本博文将详细介绍并发编程中的知识点和知识脑图,帮助大家更好的学习和使用的并发编程。 一、并发编程知识脑图 二、并发编程知识详细解析 2.1 JUC并发编程知识脑图 并发编程——知识脑图_庄小焱的博客-优快云博客 2.2 JUC并发大厂面试问题 并发编程——JUC并发大厂面试问题_庄小焱的博客-优快云博客_并发编程常见问题 2.3 JU

庄小焱 1410

JUC之并发编程

​原理​:如 AtomicInteger,其内部使用 volatile int value保证可见性,所有修改操作(如 incrementAndGet)都基于 ​CAS​ 实现,保证了原子性而无须加锁,性能极高。它维护了一个 ​volatile int state​(代表共享资源的状态)和一个 ​FIFO 线程等待队列​(CLH 队列的变体,用于管理获取资源失败的线程)。​原理​:将 AQS 的 state变量拆解使用​:高 16 位表示读锁状态(共享计数),低 16 位表示写锁状态(独占重入计数)。

YangChingyuk的博客 594
上一篇: 复杂链表的复刻(三十六)
下一篇: centos6.5安装Mysql5.5.48详细教程
software_Manito
博客等级 码龄8年 6粉丝 90原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值