JAVA多线程(一)

JAVA多线程详解(超详细) 程序:开发写的代码称之为程序。程序就是一堆代码,一组数据和指令集,是一个静态的概念。进程(Process):将程序运行起来,我们称之为进程。进程是执行程序的一次执行过程,它是动态的概念。进程存在生命周期,也就是说程序随着程序的终止而销毁。进程之间是通过TCP/IP端口实现交互的。线程(Thread):线程是进程中的实际运作的单位,是进程的一条流水线,是程序的实际执行者,是最小的执行单位。通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程。线程是CPU调度和执行的最小单位。注意。 阅读详情

前言

读完这一篇,再也不用担心线程方面的面试了

一、线程的基本概念

在操作系统中有两个混淆视听的概念叫做 进程(Process) 和 线程(Thread)

  • 进程(Process):

    进程是资源的组织单位。进程有一个包含了程序内容和数据的地址空间,以及其它的资源,包括打开的文件、子进程和信号处理器等。不同进程的地址空间是互相隔离的

  • 线程(Thread):

    线程表示的是程序的执行流程,是CPU调度的基本单位。线程有自己的程序计数器、寄存器、栈和帧等。引入线程的动机在于操作系统中阻塞式I/O的存在。当一个线程所执行的I/O被阻塞的时候,同一进程中的其它线程可以使用CPU来进行计算。这样的话,就提高了应用的执行效率。

二、在Java中线程的创建方式

注:基于我个人的习惯,对于一件事物的学习顺序来说,我更倾向于先知道怎么用,然后在使用的过程中去思考会有什么问题,然后根据问题去找答案,一步步去解决这个问题。打个比方(比方是谁具体百度),一辆汽车的制造过程 肯定是先制造出车架(车身),然后在去一步一步添加零件,去细化这些东西。

  • 继承Thread类,重写run()方法,调用start() 执行线程,其实Thread也是基于Runnable来实现的。
    static class ThreadTest extends Thread {
    
        @Override
        public void run() {
            System.out.println("Thread 线程");
        }
    }
    
    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        threadTest.start();
    }
    
  • 实现Runnable接口,重写run()方法,调用start()执行线程。
    static class ThreadTest implements  Runnable{
    
        @Override
        public void run() {
            System.out.println("Runnable 线程");
        }
    }
    
    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        threadTest.start();
    }
    
  • 实现Callable接口,重写call(),并且使用Futrue来提交我们的任务。
    static class ThreadTest implements Callable<Integer>{
       @Override
       public Integer call() throws Exception {
    	   System.out.println("Callable 线程")
           return new Integer(10);
       }
    }
    public static void main(String[] args) {
        ThreadTest ts = new ThreadTest();
        FutureTask<Integer> integerFutureTask = new FutureTask<>(ts);
        new Thread(integerFutureTask).start();
    }
    
  • 实现线程池来创建线程
        public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 3000L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程池 创建....");
            }
        });
    }
    
    
  • 基于CompletableFuture 对线程的创建,这种方式也是基于Futrue实现的
    public static void main(String[] args) {
        CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                System.out.println("当前线程名称:"+Thread.currentThread().getName());
            }
        });
    }
    

三、为什么会出现线程安全的问题呢?

说到线程安全,这里面涉及到两个概念

  • 并行

    并行是指两个或者多个事件在同一时刻发生,并行是在不同实体上的多个事件,

  • 并发

    并发是指两个或多个事件在同一时间间隔发生

在这里插入图片描述

如上图所述,我们每条线程都有属于自己的一个工作线程,线程A和线程B同时对共享变量i进行操作,在读取的过程中我们没看出什么异样,但在回写的过程中后执行的线程会覆盖先执行线程的数据,这就导致了数据不一致的问题。

由此可总结出引发线程安全的主要几个因素

  • 基础条件:共享数据
  • 共享数据出现写的情况

四、Java中是如何保证线程安全

在java高并发,多线程的程序中,势必会引起数据的一致性问题,在这一系列问题的催生下,锁就此应运而生。(本章主要讲解单机情况下)

  • 在java早期实现代码同步机制,使用的是一个叫synchronized的锁

    synchronized 常见几种用法

    1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
    2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
    3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
    4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
  • synchronized的实现原理:

    下面这段代码是引用jol提供的类来进行输出的

    public static void main(String[] args) {
      	Object o = new Object();

        String s= ClassLayout.parseInstance(o).toPrintable();
        System.out.println("========================对象未上锁之前===================================");
        System.out.println(s);
        System.out.println("========================对象未上锁之后===================================");
        synchronized (o){
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }

    }

输出结果:
在这里插入图片描述
细心的同学不难发现,对象的头部信息发生了变化,由此可见,我们使用的synchronized锁,是放在了对象的MarkWord分区中,MarkWord中默认存储的是我们的HashCode值,会随着对象的变化而变化,不同的锁状态会对应不同的存储方式,可能发生的值如下图所示:
在这里插入图片描述

synchronized锁在java中就是在对象头上面记录一些锁的信息,那最底层的源码是如何实现的呢?
这就要我们去找到C++的源码来看具体的操作

Hotspot源码目录,想自己详细研究的小伙伴可以根据下面目录找到具体的实现

  • Monitor:openjdk\hotspot\src\share\vm\runtime\objectMonitor.hpp

  • MarkWord:openjdk\hotspot\src\share\vm\oops\markOop.hpp

  • monitorenter|exit指令:openjdk\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp

  • 偏向锁:openjdk\hotspot\src\share\vm\runtime\biasedLocking.cpp

    # InterpreterRuntime::monitorenter 当前获取锁的线程
    # BasicObjectLock 基础对象锁
    IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem))
    #ifdef ASSERT
      thread->last_frame().interpreter_frame_verify_monitor(elem);
    #endif
      if (PrintBiasedLockingStatistics) {
        Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
      }
      Handle h_obj(thread, elem->obj());
      assert(Universe::heap()->is_in_reserved_or_null(h_obj()),
             "must be NULL or an object");
      // 是否开启偏向锁 在jvm的启动中 默认是开启状态 具体可自行查看
      // java -XX:+PrintFlagsFinal -version | grep BiasedLocking
      if (UseBiasedLocking) {
        // Retry fast entry if bias is revoked to avoid unnecessary inflation
        // 偏向锁逻辑
        ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
      } else {
      // 如果为开启,执行轻量级锁
        ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
      }
      assert(Universe::heap()->is_in_reserved_or_null(elem->obj()),
             "must be NULL or an object");
    #ifdef ASSERT
      thread->last_frame().interpreter_frame_verify_monitor(elem);
    #endif
    IRT_END
    

    偏向锁:ObjectSynchronizer::fast_enter的实现在 synchronizer.cpp

    void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {
    // 继续判断是否开启偏向锁
     if (UseBiasedLocking) {
     	// 是否处于安全点
        if (!SafepointSynchronize::is_at_safepoint()) {
        //通过revoke_and_rebias这个函数尝试获取偏向锁
          BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);
          //如果是撤销与重偏向直接返回
          if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
            return;
          }
        } else {
        // 如果处于安全点 撤销偏向锁 进入轻量级锁的获取过程
          assert(!attempt_rebias, "can not rebias toward VM thread");
          BiasedLocking::revoke_at_safepoint(obj);
        }
        assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
     }
    
     slow_enter (obj, lock, THREAD) ;
    }
    

    偏向锁的获取逻辑:BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);

    BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {
      assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint");
      markOop mark = obj->mark(); //获取锁对象的对象头
      //判断mark是否为可偏向状态,即mark的偏向锁标志位为1,锁标志位为 01,线程id为null
      if (mark->is_biased_anonymously() && !attempt_rebias) {
        //这个分支是进行对象的hashCode计算时会进入,在一个非全局安全点进行偏向锁撤销
        markOop biased_value       = mark;
        //创建一个非偏向的markword
        markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
        //Atomic:cmpxchg_ptr是CAS操作,通过cas重新设置偏向锁状态
        markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);
        if (res_mark == biased_value) {//如果CAS成功,返回偏向锁撤销状态
          return BIAS_REVOKED;
        }
      } else if (mark->has_bias_pattern()) {//如果锁对象为可偏向状态(biased_lock:1, lock:01,不管线程id是否为空),尝试重新偏向
        Klass* k = obj->klass(); 
        markOop prototype_header = k->prototype_header();
        //如果已经有线程对锁对象进行了全局锁定,则取消偏向锁操作
        if (!prototype_header->has_bias_pattern()) {
          markOop biased_value       = mark;
          //CAS 更新对象头markword为非偏向锁
          markOop res_mark = (markOop) Atomic::cmpxchg_ptr(prototype_header, obj->mark_addr(), mark);
          assert(!(*(obj->mark_addr()))->has_bias_pattern(), "even if we raced, should still be revoked");
          return BIAS_REVOKED; //返回偏向锁撤销状态
        } else if (prototype_header->bias_epoch() != mark->bias_epoch()) {
          //如果偏向锁过期,则进入当前分支
          if (attempt_rebias) {//如果允许尝试获取偏向锁
            assert(THREAD->is_Java_thread(), "");
            markOop biased_value       = mark;
            markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch());
            //通过CAS 操作, 将本线程的 ThreadID 、时间错、分代年龄尝试写入对象头中
            markOop res_mark = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark);
            if (res_mark == biased_value) { //CAS成功,则返回撤销和重新偏向状态
              return BIAS_REVOKED_AND_REBIASED;
            }
          } else {//不尝试获取偏向锁,则取消偏向锁
            //通过CAS操作更新分代年龄
            markOop biased_value       = mark;
            markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
            markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);
            if (res_mark == biased_value) { //如果CAS操作成功,返回偏向锁撤销状态
              return BIAS_REVOKED;
            }
          }
        }
      }
    }
    
  • CAS全称compare and swap 或者说 compare and set 译为比较并交换

    在java中 CAS是一种轻量级锁,业界有人也称之为自旋锁或无锁。在jdk中提供了一些Atomic类来对CAS进行实现,CAS呢提供了三个参数E、V、N,E代表旧值,V代表预期的旧值,N代表修改的值。所谓的比较并交换就是比较E和V的值如果相同就修改N。

    大家看如下代码

      public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
            // this 代表当前类 即为Unsafe
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    
        return var5;
    }
    

    CAS源码实现: 注:CAS源码有不同的实现方式,这里主要是atomic_linux_x86.inline.phh下的实现

    
    	inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
      int mp = os::is_MP();
      __asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
                        : "=a" (exchange_value)
                        : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                        : "cc", "memory");
      return exchange_value;
    }
    

    LOCK_IF_MP实现:

    // Adding a lock prefix to an instruction on MP machine
    #define LOCK_IF_MP(mp) "cmp $0, " #mp "; je 1f; lock; 1: "
    

    仔细阅读完如上代码,你就会发现CAS的在C++代码层面的实现了

    • lock汇编指令:可以理解为CPU指令级的一种锁。它后面可以跟ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG等指令
    • cmpxchgl汇编指令:比较并交换操作数.如:CMPXCHG r/m,r 将累加器AL/AX/EAX/RAX中的值与首操作数(目的操作数)比较,如果相等,第2操作数(源操作数)的值装载到首操作数,zf置1。如果不等,首操作数的值装载到AL/AX/EAX/RAX并将zf清0

    总结:在x86架构上,CAS被翻译为”lock cmpxchg…“。cmpxchg是CAS的汇编指令。在CPU架构中依靠lock信号保证可见性并禁止重排序,在java层面利用do{}while循环来控制自旋。

    关于锁的实现原理就讲到这里,感兴趣的小伙伴可以自行查看源码,比如说锁的释放,锁膨胀过程,锁竞争,锁升级,带着这些问题去分析源码,或者利用hsdis反编译工具来监控锁的执行状态,我相信你们都能找到属于自己的答案和理解。

五、线程池的实现原理

相信很多朋友在面试的过程中常常被问到线程池这方面的问题,核心线程数设置多少合适,最大线程数为什么要在核心线程数的基础上*2等等一系列的问题。今天我们自己来手写一个自己的线程池,来帮助大家理解线程池的一个实现原理

  • 线程池的基本概念

池化思想,统一管理线程,避免频繁创建线程,线程复用

  • 根据线程池的基本概念,手写一个自己的线程池
  1. 统一管理线程:对线程进行集中管理

    // 工作线程
    private List<WorkQue> workQues;
    // 缓存队列
    private BlockingDeque<Runnable> runnableDeque;
    
  2. 避免频繁创建线程:避免重复创建线程,顾名思义就是让线程一直在运行状态呗

        class  WorkQue extends Thread{
            @Override
            public void run() {
                while (){
                 System.sout.pringln("处于死循环,一直运行的线程")
            }
        }
    
  3. 合并到一块进行优化一下如下

    public class MyThreadPool {
        // 提前创建好的线程    顾名思义 核心线程数
        private List<WorkQue> workQues;
        // 控制线程池 启动/终止
        private boolean isE = true;
    
        private BlockingDeque<Runnable> runnableDeque;
    
    
    
        public MyThreadPool(int maxThreadPool,int maxWorkQue){
            // 任务队列 注: 定长 不然是无界队列  有缓存溢出 最大线程数 失效问题
            runnableDeque =  new LinkedBlockingDeque<>(maxWorkQue);
            // 提前创建好的 核心线程数
            workQues = new ArrayList<>(maxWorkQue);
            for (int i = 0 ; i< maxThreadPool;i++){
                new WorkQue().start();
            }
        }
    
        class  WorkQue extends Thread{
            @Override
            public void run() {
                while (isE || runnableDeque.size()>0){
                    Runnable poll = runnableDeque.poll();
                    if (poll!=null)
                        poll.run();
                }
            }
        }
    
        public  boolean execute(Runnable com){
            return runnableDeque.offer(com);
        }
    
  • 为什么阿里巴巴开发手册不推荐使用JDK自带的线程池呢?

      public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    // 采用LinkedBlockingQueue缓存队列
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }
    
    
     	public LinkedBlockingQueue() {
        	this(Integer.MAX_VALUE);
    	}
    }
    

    通过上面的代码我们也能看出来newSingleThreadExecutor创建的线程池,他的缓存队列采用的是LinkedBlockingQueue构造函数中默认的队列长度,Intrger的最大值,采用这种方式会没有限度的缓存我们的任务,可能会导致oom内存溢出的现象,还会导致我们设置的最大线程数失效的问题(关于为什么会导致最大线程数失效的问题,自行百度线程池的7个参数)

  • 核心线程数的设置

    《Java虚拟机并发编程》中提出的一个公式:线程数 = CPU 核心数 / (1 - 阻塞系数)
    下图引用自Java并发编程实战

    在这里插入图片描述

    《Java并发编程实战》中也提出了一个公式:线程数 = CPU 核心数 * (1 + IO 耗时/ CPU 耗时)

    在这里插入图片描述
    总结:线程池的核心线程数和Cpu核心数有很大的关联,但实际设置大小要根据压测以及预估来进行决定的,不同的场景应用不同的策略可以得到最合适的选择

在这里插入图片描述

【上海大学计算机组成原理实验报告】五、机器语言程序实验 机器语言程序实验//理解计算机执行程序的实际过程//学习编制机器语言简单程序的方法//将R1中的数值左移n次送OUT,其中n是R2中的数值。(指令码从10开始)//完成R3=R0×R1,结果送OUT。(指令码从30开始)//建立“中文汇编指令”需要哪些条件?//上海大学计算机组成原理实验报告 阅读详情

相关推荐

TL431过压保护电路实战:5.5V阈值设计全流程(附MOSFET选型建议)

本文详细介绍了基于TL431和MOSFET构建5.5V阈值过压保护电路的完整设计流程。内容涵盖核心原理、阈值计算、驱动电路设计,并重点针对大电流应用场景,提供了MOSFET选型与散热处理的实战建议,帮助工程师打造可靠高效的电源保护方案。

weixin_28327051的博客 540

java多线程(超详细)

进程就是正在运行中的程序(进程是驻留在内存中的)是系统执行资源分配和调度的独立单位每一进程都有属于自己的存储空间和系统资源注意:进程A和进程B的内存独立不共享。

zdl66的博客 10万+

CentOS 7下rsyslog日志服务器搭建全攻略:从安装到避坑

本文详细介绍了在CentOS 7系统上搭建rsyslog日志服务器的完整流程,从基础安装到高级配置,包括协议设置、日志模板设计、安全加固和性能优化。特别分享了生产环境中的实战技巧和常见问题解决方案,帮助用户高效构建可靠的日志管理系统。

happy2的博客 687

Java多线程的同步机制:synchronized

如果程序是单线程的,就不必担心此线程在执行时被其他线程“打扰”,就像在现实世界中,在一段时间内如果只能完成一件事情,不用担心做这件事情被其他事情打扰。但是,如果程序中同时使用多线程,好比现实中的“两个人同时通过一扇门”,这时就需要控制,否则容易引起阻塞。 为了处理这种共享资源竞争,可以使用同步机制。所谓同步机制,指的是两个线程同时作用在一个对象上,应该保持对象数据的统一性和整体性。Java 提供 synchronized 关键字,为防止资源冲突提供了内置支持。共享资源一般是文件、输入/输出端口或打印机。 在

you can you up up up的博客 1330

从仿真到流片:手把手教你优化65nm CMOS电荷泵的电流匹配与稳定性

本文详细介绍了在65nm CMOS工艺下优化电荷泵电流匹配与稳定性的工程实践指南。通过蒙特卡洛仿真、运放反馈结构版图技巧和全差分结构设计,实现优于1%的电流匹配精度和±2%以内的电流稳定性,特别针对current mismatch问题提供了有效的解决方案。

weixin_42522320的博客 417

DPABI安装教程

DPABI是是中科院心理研究所严超赣老师团队开发的一款磁共振脑影像数据分析工具包。基于SPM,在安装DPABI之前需要安装好SPM,才能正常使用。SPM的安装方法见文matlab2021a版本条件下安装spm_kidllll的博客-优快云博客 1、下载安装包 下载地址:DPABI: a toolbox for Data Processing & Analysis for Brain Imaging | The R-fMRI Network 2、将下载好的dpabi文件夹移动到matl..

qq_42356925的博客 1万+

Java基础--多线程详解

1.线程的概念; 2.线程如何使用; 3.jdk支持的基本线程池; 4.线程生命周期; 5.线程启动与终止; 6.后台线程; 7.线程继承其他类;

a18792721831的博客 7515

避开PFC设计大坑:从环路分析到参数整定的5个常见误区与解决方案

本文深入解析PFC电路设计中从环路分析到参数整定的5个常见误区,包括电感参数设计、小信号模型适用边界、电压环与电流环耦合效应等。通过实际案例和PSIM仿真数据,提供工程落地的解决方案,帮助工程师避开设计陷阱,提升电路性能与可靠性。

weixin_30666401的博客 325

Java多线程(超详细!)

1、什么是进程?什么是线程? 进程是:一个应用程序(1个进程是一个软件)。 线程是:一个进程中的执行场景/执行单元。 注意:一个进程可以启动多个线程。 eg.对于java程序来说,当在DOS命令窗口中输入: java HelloWorld 回车之后。 会先启动JVM,而JVM就是一个进程。 JVM再启动一个主线程调用main方法。 同时再启动一个垃圾回收线程负责看护,回收垃圾。 最起码,现在的java程序中至少有两个线程并发, 一个是垃圾回收线程,一个是执行main方法的主线程。 3、进程和线程是什么关系?

一只小菜鸡 15万+

【AUTOSAR-DEM】-2.1-APP SWC设置UDS/OBD DTC检出和恢复

点击返回「《Autosar_BSW高阶配置》总目录」 案例背景(共6页精讲): DEM模块提供两种不同类型的Event: • BSW-related events:DEM_EVENT_KIND_BSW(通过C-API报告 - Dem_SetEventStatus) • SW-C-related events:DEM_EVENT_KIND_SWC(通过RTE operation - SetEventStatus) 下面我们讲讲在APP SWC中设置BusOff(总线关闭) DTC故障成立/恢复(其它

「汽车电子助手」的博客 3944

掌握 Unity 中的状态机:综合指南

最后,将拥有一个由状态机驱动的功能齐全的播放器控制器,可以集成到自己的项目中。此外,状态机有助于实现复杂的人工智能、玩家控制、动画系统等,从而形成更强大、更灵活的游戏架构。状态机是计算机科学和游戏开发中的一个基本概念,它通过定义一组有限的状态及其之间的转换来模拟实体的行为。你可以定义常见的状态行为,例如 Enter、Update 和 Exit 方法,确保整个状态机架构的一致性和连贯性。由于前面提到的状态类扩展了 BaseState 类,因此我们可以为具有不同状态的不同对象创建单独的类。

yolo模型训练找我,AI游戏合作找我 1453

【牛牛送书 | 第三期】《一本书讲透Java线程:原理与实践》带你深入JAVA多线程

互联网的每一个角落,无论是大型电商平台的秒杀活动社交平台的实时消息推送,还是在线视频平台的流量洪峰,背后都离不开多线程技术的支持。在数字化转型的过程中,高并发、高性能是衡量系统性能的核心指标,越来越多的公司对从业人员的多线程编程能力提出了更高的要求。

fckbb的博客 3735

ESD防护设计宝典(二十三):ESD与EOS失效差异分析

ESD和EOS是电子制造业面临的两大挑战,随着电子产品向更高集成度、更低工作电压和更高工作频率发展,这一问题将更加突出。根据美国军方上世纪八十年代与可靠性分析中心(RAC)共同建立的现场失效返回程序(FFRP)统计数据,产品现场返回中EOS占比高达46%,而ESD仅占6%,另有6%的案例难以区分是EOS还是ESD。

m0_56451176的博客 322

《Java多线程编程核心技术》(一)多线程技能

最近阅读了一本《Java多线程编程核心技术》,总结了一下每章的知识点:第一章,java多线程技能 知识点:1,实现多线程编程的方式主要有两种:一是继承Thread类,重新run方法,二是实现Runnable接口,实现run方法,对象作为构造参数传入Thread对象进行start()启动。(第二种方式支持多继承情况)2,currentThread()方法可以返回代码段正在被哪个线程调用的信息。 Th

一名java从业者的专栏 2151

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

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

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

java多线程一

多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理“。

qq_19343089的博客 1267

VC中sqlite的使用

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

Java多线程(一)

目录Java多线程(一)前言线程与进程概念关系Thread、Runnable、 Java多线程(一) 前言 线程与进程 概念 关系 Thread、Runnable、

vodkaDL的博客 3595

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Java多线程详解(一)Java多线程入门

最近听很多面试的小伙伴说,网上往往是一篇一篇的Java多线程的文章,除了书籍没有什么学习多线程的一系列文章。但是仅仅凭借一两篇文章很难对多线程有系统的学习,而且面试的时候多线程这方面的知识往往也是考察的重点,所以考虑之下决定写一系列关于Java多线程的文章。文章参考了高老师的《Java多线程编程核心技术》。力争使用最短的篇幅把Java多线程的知识作以系统的讲述。 本节思维导图: 思维导图...

刘成 2475

Java:多线程实现龟兔赛跑(一)

题目 实现龟兔赛跑,使用多线程来完成 要求: 1、采用Math.random()取得0~1之间的随机数模拟比赛进程 2、总距离为100米, 3、在随机数0~0.3之间代表兔子跑 ,每次跑2米 4、在随机数0.3~1之间代表乌龟跑,每次跑1米 5、先跑完100米者为胜利者 思路 定义一个类继承Thread类,并重写里面的run方法 1、定义一个boolean类型的值flag记录比赛结果 2、定义一个distance表示比赛进程 3、重写run方法 run方法里面的内容为 1、使用while循环保证重复

lalala_dxf的博客 7642

Java多线程学习(一)Java多线程入门

转载地址:https://blog.csdn.net/qq_34337272/article/details/79640870 Java 并发的基础知识,可能会在笔试中遇到,技术面试中也可能以并发知识环节提问的第一个问题出现。比如面试官可能会问你:“谈谈自己对于进程和线程的理解,两者的区别是什么?” 一 进程和多线程简介 1.1 进程和线程 进程和线程的对比这一知识点由于过于基础,所以在面试中很...

weixin_39940206的博客 199

聊一聊Java多线程

Java多线程 什么是多线程? 多线程,是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。 在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。具有多线程能力的计算机因有硬件...

呼吸吐纳的博客 451

黑马java多线程窗口售票。窗口一重复原因

但在这里,休眠是在ticket++和打印之前,因此每次进入同步块后,线程会休眠10毫秒,然后执行票务操作。这可能增加了其他线程等待锁的时间,但由于非公平锁的特性,释放锁后,同一线程可能更容易再次获取锁,尤其是在高竞争情况下。synchronized使用的是非公平锁,这意味着当一个线程释放锁后,下一个获取锁的线程并不是按照等待顺序来分配的,而是可能由JVM和操作系统的线程调度器随机选择。因此,即使代码逻辑正确,某些线程(如窗口1)可能在竞争锁时更频繁地成功获取,导致其输出更多。

qq_70532748的博客 282

《Java多线程设计模式》笔记(一)

当年上学的时候看过《Java多线程设计模式》这本书,对书里的内容感觉是云里雾里,现在重看有种拨开云雾见天日的爽快。 有些多线程编码风格经常使用,有些是由JUC提供相应的实现。 这些是线程的基本介绍 常见的多线程编程规则与模式 ps:并行vs并发:http://developer.51cto.com/art/200908/141553.htm

New World 1367

JAVA多线程一

多线程 一一.概念进程与线程并行和并发多线程应用Slf4j的使用二.Java线程创建线程线程运行线程运行原理线程上下文切换常见方法线程状态三.并发之共享模型线程共享数据因为分时系统带来的问题阻塞式的解决方案 synchronized Lock变量的线程安全分析四.Monitor锁概念五.synchronized原理进阶 一.概念进程与线程 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须要把程序加载到CPU内存,这就开启了一个进程 一个进程之内可以分为多个线程,一个线程就是一个指令流,将指令

weixin_44919936的博客 995

Java多线程练习(一)线程的创建

创建三个窗口同时卖票,总票数为100 方式一:使用继承Thread类的方式 class Window extends Thread{ private static int ticket = 100; @Override public void run() { while (true){ if(ticket > 0){ System.out.println(getName() + ":卖票,票号为:" +

zhkey123的博客 228

Java多线程基础(一,java模拟面试视频

一、前言 k8s全称kubernetes,是目前大热的一个可移植容器的编排管理工具,像AWS、Azure、Google、阿里云、腾讯云等主流的公有云提供的都是基于k8s的容器服务,很多其他厂商也在努力跟进中,所以说“kubernetes”是目前容器行业中最为热门的也毫不为过! 但是大家都是知道的,kubernetes虽然比较热门,但是学习的门槛相对来说也是比较高的,所以这份笔记也是因此而生的,一经发布,瞬间上了周榜双Top1,已评钻级! 这份笔记有着以下两个重要的特点: 系统的讲解当前最流行的容器编排

m0_69377329的博客 129

java多线程系列一

我相信大家或多或少在面试中都被问到这个问题,面试宝典中也有各有各种举例,比如,线程是一个应用,一个线程中包含多个线程,线程之间独立存在。这种说法没什么问题,但是我觉得,对于java语言来说,就显得很宽泛。举个栗子,我们都用编译软件写代码把,比如idea,里面很多插件,我的idea有很多插件,snoarline,或者别的,我们在写代码的同时这些插件也同时在运行,我们可以把这些插件理解为多个线程,idea这个软件理解为一个进程。

qq_39162508的博客 750
上一篇: HashMap源码解析
人生脚步
博客等级 码龄7年 636粉丝 2原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

人生脚步

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

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

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

打赏作者

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

抵扣说明:

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

余额充值