并发与多线程

blog:https://devonmusa.github.io

1 常见概念

1.1 操作系统线程运行状态

    NEW
RUNNABLE
RUNNING
BLOCKED

1.2 Java虚拟机线程实际运行状态

     public enum State {
NEW
尚未开始的线程处于此状态,即刚创建线程对象,未调用start()方法 RUNNABLE
新建线程调用start()方法后,在Java虚拟机中执行的线程处于此状态,但它可能正在等待来自操作系统的其他资源(如处理器)。 BLOCKED
处于阻塞状态的线程正在等待监视器锁定进入同步块或同步方法,或者重入锁进入同步块或同步方法
后调用Object.wait()方法 WAITING
由于调用以下方法之一,线程处于等待状态
Object.wait(); 无超时
Thread.join(); 无超时
LockSupport.park();
例如,a.在对象上调用Object.wait()的线程正在等待另一个线程调用Object.notify()或Object.notifyAll()在该对象。
b.一个名为Thread.join(的线程正在等待指定的线程终止。 TIMED_WAITING
由于调用一个线程,线程处于定时等待状态,使线程处于定时等待状态可调用方法如下:
Thread.sleep(long);
Object.wait(long)
Thread.join(long);
LockSupport.parkNanos(long);
LockSupport.parkUntil(long); TERMINATED
终止线程的线程状态。 即线程已完成当前任务的执行。
}

1.3 重入锁

概念:

    一个线程试图获得它自己持有的锁,那么这个请求就会成功

实现原理:

   1.为每个锁绑定所有者和计数值,每重入一次该计数值自增1,而当线程每退出一次计数值递减,直到计数值为零才释放锁。

常用实现

1.4 sychroinzed

概述:

在JDK1.6之前被称为重量级锁,然后在JDK1.6中为了减少获得和释放锁所带来的性能消耗引入了偏量锁和轻量级锁

实现原理:

    JVM规范中都是给予进入和对出Monitor对象来实现方法同步和代码块同步的,但两者的实现细节不同:
代码块同步是使用monitorenter和monitorexit指令实现的

使用形式:

普通方法+syncronized

锁是当前实例对象

    public  class InstanceObjectSyncronizedTest{
private Integer num = 5; public syncronized Integer getNum(){
num++
return num;
}
}
静态方法+syncronized

锁是当前类的Class对象

    public  class InstanceObjectSyncronizedTest{
private static Integer num = 5; public static synchronized void IntegergetNum() {
++num;
}
}
方法块+syncronized(Object.Class)

锁是当前类的Class对象

 
方法块+syncronized

锁是syncronized括号里配置的对象

 

1.5 lock接口及实现

1.6 volatile

volatile是轻量级的sncronized的实现,只修饰变量,多线程访问不会发生阻塞,但volatile不具备原子性,功能使变量在多线程间可见。
  • 使用方式:

     1)确保自身状态的可见性
    2)确保他们所引用的对象的可见性
  • 应用场景:

     1)标记循环控制状态,检查状态来判断是否退出循环
    2)单线程写,多线程读

1.7 线程池

  • 拒绝策略

    重试策略

    public static class CallerRunsPolicy implements RejectedExecutionHandler {
    /**
    * Creates a {@code CallerRunsPolicy}.
    */
    public CallerRunsPolicy() { } /**
    * Executes task r in the caller's thread, unless the executor
    * has been shut down, in which case the task is discarded.
    *
    * @param r the runnable task requested to be executed
    * @param e the executor attempting to execute this task
    */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    if (!e.isShutdown()) {
    r.run();
    }
    }
    }

    异常抛出策略

    /**
    * A handler for rejected tasks that throws a
    * {@code RejectedExecutionException}.
    */
    public static class AbortPolicy implements RejectedExecutionHandler {
    /**
    * Creates an {@code AbortPolicy}.
    */
    public AbortPolicy() { } /**
    * Always throws RejectedExecutionException.
    *
    * @param r the runnable task requested to be executed
    * @param e the executor attempting to execute this task
    * @throws RejectedExecutionException always
    */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    throw new RejectedExecutionException("Task " + r.toString() +
    " rejected from " +
    e.toString());
    }

    } 旧任务丢弃策略

    /**
    * A handler for rejected tasks that silently discards the
    * rejected task.
    */
    public static class DiscardPolicy implements RejectedExecutionHandler {
    /**
    * Creates a {@code DiscardPolicy}.
    */
    public DiscardPolicy() { } /**
    * Does nothing, which has the effect of discarding task r.
    *
    * @param r the runnable task requested to be executed
    * @param e the executor attempting to execute this task
    */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
    }

    当前任务丢弃策略

    /**
    * A handler for rejected tasks that discards the oldest unhandled
    * request and then retries {@code execute}, unless the executor
    * is shut down, in which case the task is discarded.
    */
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    /**
    * Creates a {@code DiscardOldestPolicy} for the given executor.
    */
    public DiscardOldestPolicy() { } /**
    * Obtains and ignores the next task that the executor
    * would otherwise execute, if one is immediately available,
    * and then retries execution of task r, unless the executor
    * is shut down, in which case task r is instead discarded.
    *
    * @param r the runnable task requested to be executed
    * @param e the executor attempting to execute this task
    */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    if (!e.isShutdown()) {
    e.getQueue().poll();
    e.execute(r);
    }
    }
    }

2 线程安全模型

2.1 COW(copy on write)

  来源于linux的fork命令,java中的实现类CopyOnWriteArrayList 读操作无需加锁,可能会出现脏数据,遍历时被其他线程修改不会出现并发修改异常(CurrentModificationException)

2.2 CAS(compare and swap)

  即比较与替换被封装为原子操做,ConcurrentHashMap和HashMap都采用数组+链表+红黑数的结构存储数据

2.3 RWS(read write separate)

  即读写分离,LinkedBlockingQueue,用两个可重入锁枷锁head和last

3 应用场景

3.1 多读少写

3.2 多写少读

4 线程安全的类的设计

4.1 判断类是否是线程安全的

  • 找出构成对象状态的所有变量
  • 找出约束状态变量的不变性条件
  • 建立对象状态的并发访问管理策略

原文链接:https://github.com/Devonmusa/demos-parent/blob/master/language/java/doc/并发和多线程.md

Java线程安全详解的更多相关文章

  1. Java线程池详解(二)

    一.前言 在总结了线程池的一些原理及实现细节之后,产出了一篇文章:Java线程池详解(一),后面的(一)是在本文出现之后加上的,而本文就成了(二).因为在写完第一篇关于java线程池的文章之后,越发觉 ...

  2. java 线程状态 详解

    线程被创建后,有一个生命周期,下图是线程的生命周期详解. java api java.lang.Thread.State 这个枚举中给出了六种线程状态,分别是: 线程状态 导致状态发生条件 NEW(新 ...

  3. Java线程池详解

    一.线程池初探 所谓线程池,就是将多个线程放在一个池子里面(所谓池化技术),然后需要线程的时候不是创建一个线程,而是从线程池里面获取一个可用的线程,然后执行我们的任务.线程池的关键在于它为我们管理了多 ...

  4. 【java线程系列】java线程系列之java线程池详解

    一线程池的概念及为何需要线程池: 我们知道当我们自己创建一个线程时如果该线程执行完任务后就进入死亡状态,这样如果我们需要在次使用一个线程时得重新创建一个线程,但是线程的创建是要付出一定的代价的,如果在 ...

  5. Java线程池详解,看这篇就够了!

    构造一个线程池为什么需要几个参数?如果避免线程池出现OOM?Runnable和Callable的区别是什么?本文将对这些问题一一解答,同时还将给出使用线程池的常见场景和代码片段. 基础知识 Execu ...

  6. Java线程池 详解(图解)

    来源:www.jianshu.com/p/098819be088c 拓展: 手动创建 new ThreadPoolExecutor 的使用: https://segmentfault.com/a/11 ...

  7. Java 线程池详解

    Executors创建线程池 Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可,比如Executors.newFixedThreadPool(int nThreads),但 ...

  8. Java线程池详解(一)

    一.线程池初探 所谓线程池,就是将多个线程放在一个池子里面(所谓池化技术),然后需要线程的时候不是创建一个线程,而是从线程池里面获取一个可用的线程,然后执行我们的任务.线程池的关键在于它为我们管理了多 ...

  9. Java线程学习详解

    线程基础 1. 线程的生命周期 1.1 新建状态: 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态.它保持这个状态直到程序 start() 这个线程. 1 ...

  10. Java线程常用方法详解

    线程的常用方法 1.start() : 线程调用该方法将启动线程,使之从新建状态进入就绪队列排队,一旦轮到它来享用CPU资源时,就可以脱离创建它的线程独立开始自己的生命周期了. 2.run(): Th ...

随机推荐

  1. 【Python】万字长文,Locust 性能测试指北(上)

    Locust Locust 是比较常见的性能测试工具,底层基于 gevent.官方介绍 它是一款易于使用.可编写脚本且可扩展的性能测试工具,可以让我们使用常规 Python 代码定义用户的行为,而不必 ...

  2. Federated Learning004

    联邦学习--笔记004 2023.03.13周一 快中期答辩了(3.20),最近甲流高发期 毕设期间,今天学习了联邦学习的一篇论文---Differentially Private Federated ...

  3. rsync 命令

    linux上的rsync命令详解 15个rsync命令实施 -z: --compress 使用压缩机制 -v: --verbose 打印详细信息 -r: --recursive 以递归模式同步子目录 ...

  4. Java的readBytes是怎么实现的?

    1.前言 众所周知,Java是一门跨平台语言,针对不同的操作系统有不同的实现.本文从一个非常简单的api调用来看看Java具体是怎么做的. 2.源码分析 从FileInputStream.java中看 ...

  5. Trackbar调色板

    我们将会建立一个简单的应用,显示我们指定的颜色.将会建立一个窗口,显示三个trackbar指定RGB三个颜色通道值.可以滑动trackbar来改变相应的颜色.默认情况下,初始颜色为黑色. cv2.ge ...

  6. SwiftUI的认识与使用

      SwiftUI简介 SwiftUI是苹果推出的一个新的UI框架,它使用了声明的方式,通过视图,基础控件和布局控件来进行页面的开发. SwiftUI具有跨平台性,一份SwiftUI代码可以同时跑在i ...

  7. 一文搞懂TCP的三次握手和四次挥手

    目录 1.三次握手 2.四次挥手 3.11种状态名词解析 TCP的三次握手和四次挥手实质就是TCP通信的连接和断开. 三次握手:为了对每次发送的数据量进行跟踪与协商,确保数据段的发送和接收同步,根据所 ...

  8. [POI2007]GRZ-Ridges and Valleys 题解

    (2022-12-28 ) AcWing 1106 洛谷 P3456 题目大意 找出一个图中所有大于(或小于)周围相邻的非连通块点的所有连通块个数. 就是说,对于一个连通块: 如果它周围的点都低于它, ...

  9. 武汉工程大学第五届程序设计新生赛 I题 题解

    (2022,12,3) 原题链接(来自牛客竞赛) 抽象题意 题目有点长,我们需要抽象出一个模型: 一个长度为\(n\)的序列\(a_i\),从\(a_1\)开始向后跳,每次可以从\(a_i\)跳到下一 ...

  10. redux的三个概念与三大核心

    1.什么是redux?一个组件里可能会有很多的状态,比如控制某个内容显示的flag,从后端获取的展示数据,那么这些状态可以在自己的单个页面进行管理,也可以选择别的管理方式,redux就是是一种状态管理 ...