栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

深入理解Java并发编程(一)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

深入理解Java并发编程(一)

计算机基础
    要想理解Java多线程,一定离不开计算机组成原理和操作系统,因为,java的多线程是JVM虚拟机调用操作系统的线程来实现的
public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
		
		// 原生方法
    private native void start0();
    首先,先来理解CPU(处理器)的结构

解析每一个部件的功能,具体的细节不展开

ALU(算数逻辑单元):顾名思义是用来计算的,首先要知道一点,所有的信息在计算机看来都是0和1,通过加法运算,补运算, 异或运算等各种运算,完成数据的计算CU (控制单元) : 可以理解为控制ALU运算(比如运算什么,怎么运算,以及运算的次数)Register (寄存器): 用来存储ALU计算的中间数值pc(程序计数器):用来记录某个线程运行到那个指令了

    程序的加载过程以及是如何运行的

理解:程序,进程,线程

举例:比如我现在点击了WX.exe的程序,计算机会将WX程序加载到内存,这是在内存中的就是一个WX进程,每一个进程都有一个main线程,ALU找到main线程开始执行

程序:就是一段待执行的代码

进程:将程序这段代码以及所需要的数据加载到内存

线程:CPU,调度的基本单位

    再来理解一个常识性的问题:我们买的电脑几核几线程的概念

    我们可以通过cmd的命令查看一下自己的电脑(华为matebookpro)

    以我自己的电脑为例 四核八线程

wmic

获取cpu的名称 cpu get name

获取cpu的核心数 cpu get numberofcores

也可以通过更加直观的方式, 打开任务管理器

可以很直观的看出有一个插槽,四个内核,八个逻辑处理器

解释

一个插槽说明只有一个物理cpu

四个内核说明有四个ALU

八个逻辑处理器说明每个ALU可以在Register中切换,可以减少线程的挂起

以前的cpu没有使用多核和超线程技术,也就意味着一个物理cpu对应一个内核对应一个线程,效率是极其低下的

线程的安全性

    什么是线程安全?

    当多个线程访问某个类时,不管运行的环境(linux/windows)采用何种的调度方式或者这些线程将如何交替的运行,在主程序中不采用任何额外的同步或协同,这个类都可以表现出正确的行为。无状态的对象一定是线程安全的(也就是说该对象中的属性被多个线程共享)

    原子性

    要想理解原子性首先要理解几个概念

    竞态条件:

      专业术语:由于不恰当的执行顺序而出现不正确的结果的这种情况

      个人理解:线程由于cpu的调度,多个线程交替执行,要得到正确的结果需要运气成分

      // 比如在单例模式中
      if (instance == null) {
      	instance = new Singletion();
      }
      
      //这个过程是  先检查再执行,这个过程是可以被cpu打断的
      
      先检查再执行就是一个竞态条件
      
      //比如  count++
      
      //count++ 不是一步执行完成的
      
      需要先从内存中读取,在做修改,在写回内存
      
      读取 - 修改 - 写入  也是一个竞态条件
      

    复合条件:

      专业术语:一组需要以原子的方式执行(不可分割)的操作个人理解:就是不可以被cpu的调度所打断,必须执行完毕

    数据竞争:

      这个很好理解,就是多个线程可以同时去写入或读出一个变量

    加锁机制

    加锁机制可以保证原子性,也就是把一系列的操作变为原子的

    内置锁

    内置锁其实很简单,就是改变了,对象里的markword

    			// 使用这个依赖可以查看对象的结构				
    			
                org.openjdk.jol
                jol-core
                0.10
            
    
    public class JustTest {
        private static class T {
            int i;
        }
    
    		// 不加synchronized
        public static void main(String[] args) {
            T t = new T();
    
    			// 打印对象的结构
          System.out.println(ClassLayout.parseInstance(t).toPrintable());
        }
    }
    

    public class JustTest {
        private static class T {
            int i;
        }
    
        public static void main(String[] args) {
            T t = new T();
            synchronized (t) {
                System.out.println(ClassLayout.parseInstance(t).toPrintable());
            }
        }
    }
    

    重入锁

    当一个线程请求一个未被持有锁的对象,JVM会记下所得持有者,并将计数器加一,若果同一线程再次获取锁,则计数器再加一,直到计数器的个数为0时被释放

    如果不可重入,下面的代码可能就会死锁

    // 父类持有锁,不能释放,而子类需要锁,二者僵持
    public class Widget {
        public synchronized void doSomething() {
            
        }
    }
    
    class LoggingWidget extends Widget {
        
        @Override
        public synchronized void doSomething() {
            System.out.println(toString());
            super.doSomething();
        }
    }
    

    注:不是所有的数据都需要锁来保护,只有被多个线程同时访问的可变数据才需要通过锁来保护。

    活跃性和性能

    活跃性:安全性的含义:永远不要发生糟糕的事情,而活跃性则关注于:某个事情最终会发生,但由于如此,就可能出现没有得到锁而死等的现象,或者无意中造成的无限循环

    性能:性能方面有很多问题例如,服务时间过长,响应不及时等,要在性能和安全编码之间相互的权衡,不要一味为了性能而去修改简单的并发程序

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/762513.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号