java特性

3.3.1 Thread

进程和线程阐述:

java语言支持多线程,一个正在执行的java程序是一个进程,一个进程中包含多个线程,线程是单一的顺序控制流,CPU执行计算指令都是按照顺序执行,但由于其执行速度很快,可将事件分成多个时间片,交替执行。

进程和线程的区别:

                            进程创建开销大于线程,进程之间通信比线程要难。

                            线程不可独立存在,需要依托于进程,线程可看作轻量级的进程。

                            进程稳定性高于线程,进程运行不会影响其他进程,线程崩溃可能导致程序崩溃

Thread类简介:

       Thread类位于java.lang包下,JDK1.0引入,在hotspot虚拟机中,线程使用的是基于操作系统的1:1内核实现模型来创建线程,线程的创建、调度、执行、销毁由内核进行控制,调度过程通过抢占策略进行控制。

Thread类生命周期

       java语言中线程的6个生命周期,在任意时刻线程只会有1种状态,java提供了特定的api,某些场景可以实现状态的切换。6种状态使用java.lang.Thread.state枚举来表示,状态如下:

       新建(NEW):线程创建但未启动

       运行(RUNNABLE):线程正在执行或正在等待操作系统分配执行时间

       阻塞(BLOCKED):当多个线程争抢资源,等待获取一个排他锁的线程会处于该状态,线程获取到锁后状态变为RUNNABLE,其他等待锁的线程状态依旧为BLOCKED,一般使用synchronized关键字修饰或ReentrantLock包裹的代码块会触发到线程阻塞

       无限期等待(WAITING):此状态下的线程不会被分配执行时间,需要被其他线程显式唤醒。通过 对象实例.wait, 线程实例.join, LockSupport.port()等方法会使线程处于此状态

       限期等待(TIMED_WAITING):计时等待的线程,不会被操作系统分配执行时间,也不需要其他线程显式唤醒,在计时结束后由操作系统自动唤醒。以下方法可导致线程处于此状态:Thread.sleep(Long millis),object.wait(timeOut),Thread.join(Long missil)、LookSupport.parkNanos()、LookSupport.parkunti)

       终止(TERMINATED):线程执行结束后处于此状态

Thread构造方法:

  

Thread线程优先级:

创建线程方式:

              继承Thread类,重写run方法

              实现Runnable接口,重写run方法

              实现Callable接口,重写call方法。将Thread和Callable联系在一起,需要通过FutureTask

       Callable接口是JDK1.5版本后新增的接口,位于java.util.concurrent包下,call方法是run方法的增强版,可以通过实现Callable接口时传入泛型执行call方法的返回值,并可声明抛出异常。

native方法:

             Thread.yield(); 此方法表示当前线程自愿放弃对处理器的使用

              thread.join();某个线程在另一个线程之前执行

              Thread.sleep();当前线程暂停执行指定的毫秒数

              thread.iterrupt();中断线程

      

守护线程:

              通过thread.setDaemon(true)将线程设置为守护线程或用户线程。此方法必须在线程启动前调用。作用是服务非守护线程。例如垃圾回收线程就是守护线程。守护线程中产生的线程依旧是守护线程。

3.3.2 ThreadLocal

       定义:线程变量,ThreadLocal线程中填充的变量属于当前线程,对其他线程是隔离的,是当前线程独有的变量。

               ThreadLocal为变量在每个线程都创建一个副本,每个线程都可以访问自己内部的副本变量,且该副本只能由当前线程使用,所以不存在多线程共享的问题

             

       适用场景:适用于每个线程都需要自己独立的实例且该实例在多个方法中使用。即变量在线程间隔离而在方法或类间共享的场景。

       与synchronized的区别:

              相同点:都用于解决多线程并发访问

              不同点:Synchronized用于线程间的数据共享,而ThreadLocal用于线程间的数据隔离。

              Synchronized是利用锁的机制,使变量或代码块在某一时刻只能被一个线程访问;而ThreadLocal为每一个线程提供了变量的副本,使得每个线程在同一时间访问到的并非同一个对象,这样就隔离了多个线程对数据的数据共享。

                           

       ThreadLocal原理

              set方法:首先获取当前线程,然后获取线程的ThreadLocalMap属性,如果map属性不为空,则更新value值,否则先实例化ThreadLocalMap,然后初始化value

                            ThreadLocalMap是ThreadLocal的内部静态类,使用Entry来存储数据,并且继承弱引用(只能存活到下次垃圾回收之前)。

                            在Entry内部使用ThreadLocal作为key,使用设置的value作为value

              get方法:首先获取当前线程,然后获取线程的ThreadLocalMap属性,如果map属性不为空,获取map中的值,

                             否则初始化ThreadLocalMap,key为threadLocal,value为null,返回null             

              remove方法:首先获取当前线程,然后获取线程的ThreadLocalMap属性,map不为空,直接将threadLocal对应的值从map中删除

                                   删除原因:涉及到内存泄露问题;因为ThreadLocalMap中使用的key是ThreadLcoal的弱引用,而弱引用的特点在下一次垃圾回收时必然会被清理。但是value是强引用,不会被清理,这样在ThreadLocalMap就会出现key为null的value。同时ThreadLocal是与线程绑定的变量,生命周期和线程共存,而通常线程池都是采用线程复用的办法,线程很难甚至永远不会结束,意味着线程的生命周期难以预测,甚至与JVM生命周期一致。对于重复利用的线程,如果没有手动删除对应key,就会导致(null,value)的对象越来越多,从而导致内存泄露

              Thread、ThreadLocal、ThreadLocalMap之间的关系:ThreadLocalMap是Thread线程的属性,ThreadLocal是维护ThreadLocalMap的工具类。

                                                                                              Thread线程可以拥有多个ThreadLocal维护的线程独享变量。

       常见使用场景

              1.每个线程需要有自己单独的实例

              2.实例需要在多个方法中共享,但不希望被多线程中共享

      

       正确使用方式:

              将ThreadLocal定义成private static,这样ThreadLocal生命周期更长,并且是强引用,不会被回收清理,可以保证任何时候都可以通过threadLocal的弱引用访问到Entry的value值

              每次使用完ThreadLocal,务必调用remove方法清除数据,避免内存泄露

      

参考资料:https://blog.csdn.net/u010445301/article/details/111322569   

                https://blog.csdn.net/u010445301/article/details/124935802

3.3.3 Synchronized

       1.定义:java关键字。

       2.作用:保证同一时刻最多只能有1个线程执行被synchronized修饰的代码块或方法

       3.应用场景:保证线程安全,解决多线程的并发同步问题(实现的是阻塞型并发)

                       具体场景如下:

                            1.修饰实例方法/代码块,(同步)保护的是同一个对象方法的调用&实例对象

                            2.修改静态方法/代码块:(同步)保护的是静态方法的调用&类对象

       4.原理:

              1.依赖JVM实现同步

              2.底层通过一个监视器(monitor)对象完成,wait,notify方法也依赖monitor对象

                     监视器锁(monitor)的本质依赖于底层系统的互斥锁(Mutex Lock)实现

       5.具体使用:

              5.1 使用规则

                     5.1.1 锁对象设置

                            a:修饰代码块时,需要一个reference(引用)对象作为锁的对象

                            b:修饰实例方法时,默认锁对象是当前实例对象

                            c:修饰静态方法时,默认锁对象是当前类的class对象

                     5.1.2 根据锁对象的不同,一把锁同时最多只能被一个线程持有

                            若目标锁已被当前线程持有,其他线程只能阻塞等待当前线程释放目标锁

                            若当前线程持有目标锁,其他线程仍然可以访问类中无synchronized修饰的方法

                     5.1.3 当对象获取多个锁时,必须以相反的顺序释放&在与所有锁被获取时相同的词法范围内释放所有锁

                            若线程进入由线程已拥有的监控器保护的synchronized块,就允许线程继续执行

                            只有线程推出它进入的第一个synchronized块时,才释放锁

                     5.1.4 注意

                            java类中,实例对象可以有多个,类对象只能有1个(类的不同实例共享该类的class对象)

                            静态方法&实例方法上的锁默认不一样,静态方法加锁,和其他所有加锁的静态方法互斥

              5.2 锁的类型&等级

                     对象锁:

                            定义:含synchronized方法/代码块的类的实例对象

                            作用:控制同步方法之间的同步

                            锁对象:实例对象

                            锁数量:多个

                            表示形式:修饰实例方法或实例代码块

                            应用场景:控制实例方法之间的同步

                            使用:

                                   使用前必须先获得对象的锁(线程进入synchronized方法时获取对象锁,若此时对象锁已被其他线程占用,则需等待此锁被释放后才能调用)

                                   java所有对象都有一个互斥锁,此锁由JVM自动获取和释放

                                   synchronized正常返回or抛出异常终止,JVM都会自动释放对象锁

                     方法锁(也属于对象锁):

                            定义:使用synchronized修饰的方法

                            作用:控制同方法之间的同步

                            锁对象:实例对象

                            锁数量:多个

                            表示形式:修饰实例方法或实例代码块

                            应用场景:控制实例方法之间的同步

                            使用:synchronized方法控制对类成员变量的访问

                     类锁:

                            定义:使用synchronized修饰静态方法/静态代码块(类锁实际上就是锁Class对象,具体表现是 锁静态方法/静态代码块)

                            作用:控制静态方法之间的同步

                            锁对象:类对象

                            锁数量:1个

                            表示形式:修饰静态方法或静态代码块

                            应用场景:控制静态方法之间的同步

                            使用:一个静态方法被synchronized修饰,此类所有实例化对象在调用此方法时,共用同一把锁

                                     一个类不论实例化多少次,其静态方法在内存中始终只有1份

              5.3 注意

                     使用synchronized修饰较大方法,存在一定缺陷,将会大大影响效率;

                     例如:使用synchronized方法修饰线程类的run方法,由于run()方法在线程整个生命周期内一直运行,因此将导致本类的其他synchronized方法永远被阻塞

                     解决办法:使用synchronized修饰代码块 & 任意指定上锁的对象。精确锁定需要同步指定的代码片段,避免无需同步的代码进行同步,影响效率

                     synchronized(syncObject){}

       6. 特点

              保证原子性(一个操作/一系列操作 要么全部执行,要不全部不执行)、可见性(某个线程修改了共享属性的值,其他线程可立刻看到共享属性的值)、有序性(程序运行顺序和编码顺序一致,但计算机实际执行并不一定)

              可重入性:某个线程获取锁后,调用其他需要同样锁的代码时可直接调用

              重量级:底层通过monitor(监视器)对象完成,wait,notify等方法也依赖monitor对象

                            监视器锁的本质依赖于底层操作系统的互斥锁(Mutex Lock)实现,而操作系统实现线程切换需要从用户态转换到内核态

                            上述执行时间较长,所以synchronized效率低&重量级

       7.其他控制并发/线程同步方式

              7.1 Lock、ReentrantLock

              7.2 CAS Compare and swap(比较并交换) ,是一种解决并发操作的乐观锁;而synchronized是同一时刻只能由一个线程执行,属于悲观锁

       参考资料:https://blog.csdn.net/carson_ho/article/details/82992269

                       https://blog.csdn.net/weixin_43849277/article/details/108358035

                       https://blog.csdn.net/weixin_36759405/article/details/83034386

3.3.5 java.util.concurrent

       1.定义:是java中用于并发编程的重要工具集,提供了线程池、原子变量、并发集合、同步工具类、阻塞队列等一系列高级并发工具类,

                     使用这些工具类可以极大的简化并发编程的难度,减少出错的可能性,提高程序的效率和可维护性。

       2.内容细分

              2.1 Executor FrameWork 执行器框架

                     定义:Executor FrameWork提供了标准的方法来启动、管理和控制线程的执行,执行器框架主要由接口和类构成,

                              如Executor、Executors、ExecutorService、Runnable、Callable等。这些组件共同协作,提供了灵活高效的线程管理机制

                     关键组件说明:

                            Executor:基本接口,定义execute方法,用于接收实现runnable接口的对象,并启动新线程执行该对象的run方法

                            Executors:工具类。提供了多种类型线程池的创建方法,如newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool等。这些线程池内部实际上

                                                 都是实现了ExecutorService接口的对象

                            ExecutorService:继承自Executor 接口,添加了一些管理和控制线程的方法,如shutdown、shutdownNow、awaitTermination(等待所有任务执行完毕关闭线程池)

                            Future和Callable接口:两接口通常一起使用,callable接口类似runnable接口,区别就是由返回值,并且可以抛出异常;

                                                                 Future表示异步计算的结果,提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。

              2.2 并发集合 Concurrent Collections

                     定义:是用于支持并发编程的一组数据结构,用于避免多线程访问修改共享数据,可能出现的数据不一致和其他并发问题。

                     常见并发集合类:

                            ConcurrentHashMap:线程安全的HashMap,支持多个线程同时读写映射表,而不会相互阻塞

                            CopyOnWriteArrayList:线程安全的ArrayList;修改时复制底层数组来实现线程安全;读取操作在内部数组的快照上进行,无需锁定;写入时是创建新的数组副本,修改之后原子地将其替换为当前数组

                            ConcurrentLinkedQueue:基于链接节点的无界线程安全队列,按照FIFO(先进先出)原则对元素进行排序,多线程安全并发访问此队列,使用高效非阻塞算法实现

                            ConcurrentSkipListMap和ConcurrentSkipListSet:基于跳表(Skip List)数据结构实现的并发有序集合,与TreeMap和TreeList类似,但是支持更高并发的读写

                            ConcurrentLinkedDeque:线程安全的双端队列,允许多个线程并发访问

                            BlockingQueue接口及其实现:线程安全队列。检索队列如果队列为空会阻塞线程,直至队列中有元素;添加元素如果队列已满会阻塞线程,直至队列有空间。

                                                                        ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue和SynchronousQueue等都是此接口的实现

              2.3 Atomic Variables 原子变量

                     定义:并发编程中实现线程安全的一种机制,原子变量提供了在多线程环境中安全读取、修改、更新变量的方式;

                     常用原子类:java.util.concurrent.atomic.AtomicInteget、AtomicLong、AtomicBoolean等

              2.4 Synchronizers 同步器

                            定义:java并发编程中用于协调线程之间同步的组件,提供了机制,使线程能等待、通知、限制其他线程的执行。有效的避免死锁、竞态条件和其他线程问题。

                            主要类:

                                   ReentrantLock:可重入锁,一个线程可以多次获取同一个锁,而不会导致死锁;支持公平锁和非公平锁;底层通过AQS链接实现

                                   CountDownLatch:同步辅助工具,允许一个或多个线程等待其他线程完成一系列操作。初始化需要设置一个计数值,每个在其任务完成后调用countDown减少计数值,当计数值减少至0时,所有等待线程都会被唤醒

                                   CyclicBarrier:同步辅助工具,允许一组线程相互等待,直到所有线程达到某一个状态后再一起运行。初始化时会设置一个屏障的初始阶段数,线程完成任务后调用await方法进行等待,当阶段数减少至0时,所有线程继续执行

                                   Semaphore:信号计数器,提供了对资源的精细控制,维护了一个许可证书,只有当获取许可证书的线程才能访问受保护的资源,当线程完成了对资源的访问,会释放许可证,允许其他线程获得许可证。

                    

       参考资料:https://zhuanlan.zhihu.com/p/651441418

                       https://blog.csdn.net/qusikao/article/details/135705993

                       https://blog.csdn.net/qq_45871274/article/details/130462252

                       https://blog.csdn.net/outsanding/article/details/111126726

                       https://blog.csdn.net/CNCDXX_88/article/details/129119877

                       https://blog.csdn.net/fanrenxiang/article/details/80623884

3.3.6 Lock

       路径:java.util.concurrent.locks.Lock

       类型:interface

       定义:类似于synchronized块的同步机制

       与synchronized的区别:

              synchronized是关键字;Lock是接口

              synchronized无需手动释放锁;Lock需要手动进行释放锁,如果未释放,可能出现死锁

              Lock可以配置公平策略,实现线程按照先后顺序获取锁

              Lock提供了trylock方法,可以试图获取锁,获取成功或失败,有不同的返回值,可让程序灵活处理

              lock方法和unlock方法可以在不同的方法中执行,比synchronized更加灵活

       抽象方法:

              void lock(); :获取锁,如果锁不可用,则出于线程调度目的,当前线程将被禁用,获取锁之前处于休眠状态

              boolean trylock(); :尝试获取锁,可用返回true,不可用返回false

              boolean trylock(long time,TimeUnit unit) throws InterruptedException ;尝试获取锁,如果锁可用返回true,不可用,则出于线程调度目的,禁用当前线程,并设置状态为休眠,直到以下三种情况之一为止(当前线程获取到锁;当前线程被中断,并且支持中断获取锁;经过指定等待时间获得了锁返回true,未获取到依旧返回false)

       参考资料:https://blog.csdn.net/m0_50370837/article/details/124471888

3.3.7 ReentrantLock

       路径:java.util.concurrent.locks.ReentrantLock

       类型:class。实现了Lock接口

       定义:重入锁,也叫做递归锁。同一线程外层函数获得锁之后,内层函数仍然有获取该锁的代码,但不受影响,可避免死锁问题。synchronized也可重入。

       可重入测试:编写类实现runnable接口,实例化ReentrantLock。编写两个方法,方法中使用同一个lock进行锁定和释放锁,并且其中一个方法调用另外一个方法,重写的run方法中调用包含另一个方法的方法,启动线程,两个自定义方法都会执行。

       参考资料:https://blog.csdn.net/m0_50370837/article/details/124471888

                       https://blog.csdn.net/zhengzhaoyang122/article/details/110847701

                       https://it-blog-cn.com/

3.3.8 CAS

1.定义:比较并替换,轻量级的线程同步机制,可在不使用锁的情况下,对共享数据进行线程安全的操作

2.思想:三个参数,内存值V,旧的预期值A,新值B,当预期值A和内存值V相同时,将内存值V更新成B,否则什么都不做。此过程是原子操作,底层依赖于CPU的原子指令

3.原理相关的Usafe类:JDK提供的不安全的类,提供了底层的操作,作用是让java直接操作内存,提高效率。大多都是一些native方法,直接交由JVM或c++去实现。

参考资料:https://blog.csdn.net/Aqting/article/details/129465893

                https://blog.csdn.net/yujing1314/article/details/105943128

3.3.9 Java线程和Linux线程的联系

java线程的实现方式,是内核线程的实现方式。这种方式是直接由操作系统内核完成线程切换,内核通过操纵调度器(Thread Scheduler)实现线程调度,并将线程任务反映在各个处理器上。

虽然线程是由内核线程实现,但是程序并不直接使用内核线程,而是使用内核线程的高级接口-轻量级进程(LWP)(即是线程)

KLT:内核线程/内核分身

LWP:轻量级进程/线程

大型程序开辟的线程数量至少等于机器的CPU内核数量           

java使用 Runtime.getRuntime().availableProcessors(); 获取CPU内核数量 

如果线程有一半的时间是阻塞,线程数量应为内核数量的2倍

线程数量=内核数量/(1-阻塞率)

参考资料:http://www.hongyanliren.com/2015m07/35068.html

  • 13
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值