1.基础知识

  • java默认的两个线程:Main线程+GC守护线程

  • java并不能开启线程,需要调用底层用c语言写的本地方法

  • wait和sleep的区别:

    wait方法会释放线程锁,并且只能在同步代码块中使用,sleep带锁睡眠,可以在任一地方睡眠

  • Synchronized锁和lock锁的区别

    Synchronized会自动释放锁,lock需手动释放,不然会造成死锁

    Synchronized线程会持续等待直到获得锁,而lock锁的tryLock()方法避免了死等

    Synchronized(可重入锁、公平锁、非中断锁)

    Lock(可重入锁、默认非公平锁(可设置公平)、可中断锁)

  • java对象布局

    1.对象的实例属性

    2.对象头(12byte)

    • MarkWord
    • Class Metadata Address(Class Pointer)

    3.数据对齐 (1+2的总大小不是8byte的倍数使用于补齐)

    好博客分享:[https://blog.csdn.net/Mr_wxc/article/details/107710945?utm_medium=distribute.pc_relevant.none-task-blog-2~default~OPENSEARCH~default-16.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~OPENSEARCH~default-16.control]

  • Condition监视器

    与lock配套为了代替原wait和notify

    Condition con = lock.newCondition();//创建监视器对象
    con.await();//线程等待
    con.signal();//线程唤醒

    condition监视器可以创建多个监视器对象同时监视多个线程,可以达到控制线程执行的效果

  • 集合的线程不安全

    线程不安全的集合在进行线程修改时会几率报出并发修改异常ConcurrentModificationException

    线程安全的集合:Vector、Hashtable、ConcurrentHashMap、Stack

    集合线程不安全的解决办法

    1.用线程安全的集合替代

    2.用Collections.synchronized+集合名系列集合,如:

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

    3.用CopyOnWrite系列集合(写时复制)

    相比1、2方法,方法3使用的是lock锁,效率要高于synchronized锁,其次写时复制的意思是多个线程修改的是原集合的副本,在修改完成后再写回原集合,所以lock锁是加在副本上的,原集合此时依然可以被只读线程获取,加快了读写效率,代价是副本内存占用和数据实时性。

    map集合没有CopyOnWrite,但有一个等效的ConcurrentHashMap

    这里推荐一个CSDN博主!(https://blog.csdn.net/weixin_44460333/article/details/86770169)

  • 常用辅助类

    CountDownLatch 减法计数器

    CountDownLatch latch = new CountDownLatch(10);//初始化为10
    for (int i = 0; i < 10; i++) {
    new Thread(()->{
    latch.countDown();//计数器减一
    }).start();
    }
    latch.await();//等待计数器归零
    System.out.println("执行完毕");

    CyclicBarrier 线程加计数器

     CyclicBarrier barrier = new CyclicBarrier(10,()->{
    System.out.println("顶级线程执行");//线程计数达到10之后执行该线程
    });
    for (int i = 0; i < 10; i++) {
    new Thread(()->{
    barrier.await();//线程计数器加一
    }).start();
    }

    Semaphore信号量

    Semaphore semaphore = new Semaphore(5);
    //同一时间内只能有5个线程“执行”,并发限流
    for (int i = 0; i < 10; i++) {
    new Thread(()->{
    try {
    semaphore.acquire();
    System.out.println(Thread.currentThread().getName()+"抢到车位");
    TimeUnit.SECONDS.sleep(5);
    semaphore.release();
    System.out.println(Thread.currentThread().getName()+"离开车位");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    },""+i).start();
  • ReadWriteLock 读写锁

        private ReadWriteLock lock = new ReentrantReadWriteLock();
    //读锁
    lock.readLock().lock();
    ...//业务代码
    lock.readLock().unlock();
    //写锁
    lock.writeLock().lock();
    ...//业务代码
    lock.writeLock().unlock();
    }
  • Blocking Queue 阻塞队列

    • 队列的四组API
    方法功能 抛出异常 不抛出异常,返回值 阻塞等待 超时等待
    添加元素 add() offer() put 重载offer
    删除元素 remove() poll() take 重载poll
    判断队列头 elment() peek()

    重载offer(Object,long timeOut(等待时间),TimeUnit(时间单位))

    重载poll(long timeOut(等待时间),TimeUnit(时间单位))

    • SynchronousQueue同步队列

    队列中只能有一个元素,当队列中有元素时,不允许添加其他元素,只有当该元素被移除,才能继续添加

2.线程池

  • Executors

    ExecutorService threadpool = Executors.newCachedThreadPool();//伸缩池
    //ExecutorService threadpool = Executors.newFixedThreadPool(5);//固定大小的池
    //ExecutorService threadpool = Executors.newSingleThreadExecutor();//单个线程的池
    for (int i = 0; i < 100; i++) {
    threadpool.execute(()->{//创建线程
    System.out.println(Thread.currentThread().getName()+" is Running");
    });
    }
    threadpool.shutdown();
    //一般不使用executors创建线程池,高并发下容易报出oom
  • 七大参数

    public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
    int maximumPoolSize,//最大线程数量
    long keepAliveTime,//线程存活时间
    TimeUnit unit,//时间单位
    BlockingQueue<Runnable> workQueue,//阻塞队列
    ThreadFactory threadFactory,//线程工厂
    RejectedExecutionHandler handler) {//拒绝策略
    ...
    }
    ```
  • 四种拒绝策略

    ThreadPoolExecutor executor = new ThreadPoolExecutor(3,5,2,//自定义线程池
    TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),
    Executors.defaultThreadFactory(),
    //拒绝策略
    //new ThreadPoolExecutor.AbortPolicy()//阻塞队列满,抛出异常
    //new ThreadPoolExecutor.CallerRunsPolicy()//由原调用线程执行(哪来回哪去)
    //new ThreadPoolExecutor.DiscardPolicy()//阻塞队列满,不会抛出异常
    new ThreadPoolExecutor.DiscardOldestPolicy()//阻塞队列满,不会抛出异常,和最早进入阻塞队列的线程竞争
    );
  • 最大线程数该如何定义

    cpu密集型,最大线程数=内核数

    Runtime.getRuntime().availableProcessors();//获取计算机核数

    io密集型,最大线程数>占用IO大的线程数

3.接口

  • 四大函数式接口

    public interface Function<T, R> {
    //输入T型,返回R型
    R apply(T t);//需实现apply方法
    }
    public interface Predicate<T> {
    //输入T型,返回布尔型
    boolean test(T t);//需实现test方法
    }//断定型接口
    public interface Consumer<T> {
    //只有输入、没有输出
    void accept(T t);//需实现accept方法
    }//消费型接口
    public interface Supplier<T> {
    //只有返回值,没有输入
    T get();//需实现get方法
    }//供给型接口
  • Stream流式计算

    //存储交给集合,计算交给流
    list.stream()
    .filter(u->{return u.getId()%2==0;})//筛选偶数id的用户
    .filter(u->{return u.getAge()>22;})//筛选年龄大于22的用户
    .map(u->{return u.getName().toUpperCase();})//将用户名转换为大写
    .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})//将用户名倒序排序
    .limit(1)//限制输出个数为1
    .forEach(System.out::println);//便利打印

4.JMM

  • JMM内存模型

  • 内存交互八大操作及其约束

    1.lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态

    2.unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

    3.read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用

    4.load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中

    5.use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令

    6.assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中

    7.store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用

    8.write  (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中

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

    1.不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write

    2.不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存

    3.不允许一个线程将没有assign的数据从工作内存同步回主内存

    4.一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量实施use、store操作之前,必须经过assign和load操作

    5.一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解锁

    6.如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值

    7.如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量

    8.对一个变量进行unlock操作之前,必须把此变量同步回主内存

    来自【https://zhuanlan.zhihu.com/p/29881777】

  • volatile关键字

    1.保证线程可见性,不保证原子性(保证原子性可以用Lock、synchronized、Semaphore(信号量)、原子类(java.util.concurrent.atomic))

    2.禁止指令重排(内存屏障)

  • CAS

    CAS(Compare And Swap)比较并替换。

    CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。

    更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B,预期值不一样时,将会通过循环获取预期值进行CAS(底层用自旋锁实现)。

    CAS会导致ABA问题(即内存地址中的值可能在该线程执行过程中被修改之后再改回来,导致CAS提交时预期值和内存地址中的值相同,修改成功)

    可以通过原子引用解决这个问题:

    AtomicStampedReference<T> stampedReference =
    new AtomicStampedReference(T,version版本号);
    stampedReference.compareAndSet(T_预期值,T_修改值,原始版本号,新版本号);
    stampedReference.getReference();//获取当前版本号

Java基础篇——JUC初步的更多相关文章

  1. java基础篇---I/O技术

    java基础篇---I/O技术   对于任何程序设计语言而言,输入输出(I/O)系统都是比较复杂的而且还是比较核心的.在java.io.包中提供了相关的API. java中流的概念划分 流的方向: 输 ...

  2. 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇

    Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...

  3. java基础篇---HTTP协议

    java基础篇---HTTP协议   HTTP协议一直是自己的薄弱点,也没抽太多时间去看这方面的内容,今天兴致来了就在网上搜了下关于http协议,发现有园友写了一篇非常好的博文,博文地址:(http: ...

  4. java基础篇---I/O技术(三)

    接上一篇java基础篇---I/O技术(二) Java对象的序列化和反序列化 什么叫对象的序列化和反序列化 要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象 ...

  5. Java基础篇 - 强引用、弱引用、软引用和虚引用

    Java基础篇 - 强引用.弱引用.软引用和虚引用 原创零壹技术栈 最后发布于2018-09-09 08:58:21 阅读数 4936 收藏展开前言Java执行GC判断对象是否存活有两种方式其中一种是 ...

  6. java基础篇 之 构造器内部的多态行为

    java基础篇 之 构造器内部的多态行为 ​ 我们来看下下面这段代码: public class Main { public static void main(String[] args) { new ...

  7. 小白—职场之Java基础篇

    java基础篇 java基础 目录 1.java是一种什么语言,jdk,jre,jvm三者的区别 2.java 1.5之后的三大版本 3.java跨平台及其原理 4.java 语言的特点 5.什么是字 ...

  8. java基础篇1

    JAVA基础篇1 注释 单行注释 //这是一个单行注释,由两个斜杠组成,不能嵌套多行注释 多行注释 /*这是一个 多行注释 ,//里面不能嵌套多行注释, 但是可以嵌套单行注释*/ 文档注释 /**ja ...

  9. Java基础篇(JVM)——类加载机制

    这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...

  10. Java基础篇(JVM)——字节码详解

    这是Java基础篇(JVM)的第一篇文章,本来想先说说Java类加载机制的,后来想想,JVM的作用是加载编译器编译好的字节码,并解释成机器码,那么首先应该了解字节码,然后再谈加载字节码的类加载机制似乎 ...

随机推荐

  1. 6.-Django设计模式及模版层

    一.MVC (java等其他语言) MVC代表Model-view-Contorller(模型-视图-控制器)模式 M模型层主要用于对数据库层的封装 V视图层用于向用户展示结果 C控制器用于处理请求. ...

  2. 18.-cookies和session

    一.会话定义 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次绘画 HTTP协议是无状态的,导致绘画状态难以保持 Cookies和session就是为了保持会话状态而诞生的两个存储技术 ...

  3. 使用dotnet-monitor sidecar模式 dump docker运行的dotnet程序.

    前情概要 随着容器和云技术的发展, 大量的应用运行在云上的容器中, 它们的好处是毋庸置疑的, 例如极大的提高了我们的研发部署速度, 快速的扩缩容等等, 但是也存在一些小小的问题, 例如难以调试. 基于 ...

  4. Mysql之MGR高可用实战案例

    MGR高可用实战案例 1.环境准备 node1 rocky8.6 10.0.0.8 node2 rocky8.6 10.0.0.18 node3 rocky8.6 10.0.0.28 2.所有节点更改 ...

  5. redux中间件

    Redux 中间件 什么是中间件? 中间件本质上就是一个函数,Redux允许我们通过中间件的方式,扩展和增强Redux应用程序,增强体现在对action处理能力上,之前的计数器与弹出框案例中.acti ...

  6. scrapy 如何使用代理 以及设置超时时间

    使用代理 1. 单文件spider局部使用代理 entry = 'http://xxxxx:xxxxx@http-pro.abuyun.com:xxx'.format("帐号", ...

  7. 如何通过Java导出带格式的 Excel 数据到 Word 表格

    在Word中制作报表时,我们经常需要将Excel中的数据复制粘贴到Word中,这样则可以直接在Word文档中查看数据而无需打开另一个Excel文件.但是如果表格比较长,内容就会存在一定程度的丢失,无法 ...

  8. C#多线程之高级篇(上)

    前言 抛开死锁不谈,只聊性能问题,尽管锁总能粗暴的满足同步需求,但一旦存在竞争关系,意味着一定会有线程被阻塞,竞争越激烈,被阻塞的线程越多,上下文切换次数越多,调度成本越大,显然在高并发的场景下会损害 ...

  9. selenium被某些网页检测不允许正常访问、登录等,解决办法

    网站通过什么方式检测 function b() { return "$cdc_asdjflasutopfhvcZLmcfl_"in u || d.webdriver } 通过上方的 ...

  10. 基于.NET 7 的 WebTransport 实现双向通信

    Web Transport 简介 WebTransport 是一个新的 Web API,使用 HTTP/3 协议来支持双向传输.它用于 Web 客户端和 HTTP/3 服务器之间的双向通信.它支持通过 ...