java基础总结#多线程

xiaoxiao2021-02-28  120

1.进程:正在运行的程序,是系统进行资源分配的独立单位。 2.线程:进程的执行路径,调度和执行的单位,单个路径单线程,多个路径多线程。 本质区别:每个进程拥有自己的一套变量,而线程只是共享数据。 多进程的意义:提高CPU的使用率。 多线程的仪的意义:提高应用程序的效率 3.创建多线程的三种基本方式: ①继承Thread类,重写run方法,自定义类的实例,调用start() 方法启动线程 ②实现runnable接口,重写run方法,自定已类的实例,调用start()方法启动线程。 ③采用Excuter创建线程池 ①vs②vs③优势: a:单继承的局限性 b:更好的体现面向对象的分离(线程和程序的分离) c:适合多个 程序去处理同一资源的区别,线程池也是非常高效的,很容易实现和使用 无限制创建线程的不足:①线程生命周期的开销非常高②资源消耗(活跃的线程会消耗系统资源,当可运行的线程大于处理器的数量势必造成大量空闲线程等待)③稳定性(在创建线程的数量上存在一个限制(随不同平台而定),如果打破这个限制就容易出现OutMemoryException) 4 start()方法 和run()方法的区别 ①run方法仅仅是封装线程执行的代码,直接调用是普通方法。 ②start方法是启动线程,由java去调用run()方法。 5.线程的两种调度模型 ①分时调度模型:所有线程轮流使用cpu的使用权,平均分配每个线程占用cpu的时间。 ②抢占式调度模型:有限让优先级高的线程使用cpu,如果优先级相同,则随机选择一个,优先级高的获取cpu的时间片多一点。 java采用的是抢占式调度模型、优先级最高的死10,最低为1,多个抢占,一个运行。 6线程的五个状态 新建状态:创建线程对象 待运行:线程调用start()之后,有执行的资格,没有执行权。 运行:获得cpu执行权(当加锁保证线程安全时胡进入锁池等待获取锁,即同步阻塞) 阻塞: ①等待阻塞:object的wait()方法调用后,进入等待队列,唤醒后进入锁池,获得锁后又回到待运行状态。 ②同步阻塞:争抢cpu使用权,没抢到手,进入锁池等待获得锁。 ③其他阻塞:如sleep(),join(),时间结束后进入待运行装填。 死亡:run,main执行结束,或因异常退出 线程终止的两大原因:当线程的run方法执行方法体中最后一条语句后,并经由return语句返回时,或者出现没有捕获的异常时,线程终止。 7.wait()方法和sleep()方法: 相同点 ①在多线程环境下调用可阻塞指定的秒数,并返回。 ②二者度可以抵用interrupt()方法打断线程的暂停状态 不同点 ①每个对象独有一个锁来控制同步访问,synchronized关键字可以和对象的锁交互,来实现线程的同步。sleep()方法没有释放锁,而wait方法释放锁,使得其他线程可以使用同步控制块或者方法。 ②wait()。notify ,notifyall只能在同步方法或者同步控制块中使用,而sleep方法可以在任何地方使用 ③sleep是线程类的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复。 ④wait是object的方法,调用会放弃对象锁,进入等待队列,待调用notify唤醒指定的线程或者notifyAll唤醒所有线程,才会进入锁池,当获得对象锁,进入运行状态。 8.产生线程安全问题 ①是否是多线程环境 ②是否有共享数据 ③是否有多条语句操作共享数据 以上三个问题同时出现会出现线程安全问题 解决问题:把多个语句操作共享数据的代码给锁起来,让任意时刻只有一个线程执行即可。 9.同步安全的两种机制 ①Synchronized关键字 内部对象锁,只有一个相关条件,且每一个对象都有一个内部锁,为了使线程面对的是同一把锁,对象要生成于类中,同步方法的锁是this,静态方法的锁是本类的字节码对象class ②ReentrantLock类,实现了Lock接口。它的lock方法(一般放置于try中)和unlock方法(一般放置与finally中) 主要区别: a,lock不再用synchronize代码包装起来 b,阻塞需要另一种对象condition c,同步和唤醒的对象是condition而不是lock,对应的方法是await和signal 例: 线程 woker

synchronize (obj){ obj.wait(); }

线程manager

synchronize(obj){ obj.notify(); }

使用ReentrantLock

lock.lock(); condition.await(); lock.unlock(); lock.lock(); condition.signal(); lock.unlock();

lock更加灵活,以前的方式只有个等待队列,在实例应用中可能需要多个,为了灵活性,lock将同步互斥和等待队列分开来,互斥保证在某个时刻有一个线程访问临界区,等待队列负责保存被阻塞的线程。 内部对象只有一个相关条件,wait方法将一个线程添加到等待集中,由锁来管理那些试图进入synchronize方法的线程,由条件来管理那些调用wati的线程,一个锁对象可以有一个或者多个相关的条件对象。 10 线程池 使用场景:程序创建了大量生命周期很短的线程,应该使用线程池。 主要解决处理器单元内多个线程的执行问题,可以显著减少处理器单元的闲置时间,增加单元处理器的吞吐能力,减少并发线程的数目。 一个线程池包含很多空闲的线程,将runnable对象交给线程池,就会有一线程调用run方法,当run方法退出后,线程不会死亡,而是在池中准备下一个请求提供服务。 java通过Excutors提供四中线程池: ①newCachedThreaPool创建一个可缓存线程池,如果线程池的长度超过处理需要,可灵活回收空闲线程,若无可回收,则会建立新线程。 ②newFixedThreadPool创建一个定长线程,超出的线程会在队列中等待。 ③newScheduledThreadPool创建一个定长线程,会定期及周期性任务执行。 ④newSinglThreadPool创建一个单线程的线程池,它会用唯一的工作线程来执行任务,保证所有任务按照指定的顺序完成。 11 线程池与new Thread的比较 new Thread 的弊端: ①每次 new Thread 新建对象性能差 ②线程缺乏统一的管理,可能无限制新建线程,相互之间竞争,及可能过多的占用系统资源导致死机, ③缺乏更多的功能,如定时执行,定期执行,线程中断。 线程池优势: ①重用存在的线程,减少对象创建、消亡的开销,性能佳。 ②可有效控制最大并发线程数,提高系统资源的使用率,减少过多资源竞争,避免阻塞。 ③提供定时执行、定期执行、单线程、并发数控制等功能。 ThreadPoolExecutor的内部工作原理 1.如果当前池大小poolsize小于corePoolSize,则创建新线程执行任务 2.如果当前池大小poolSize大于corePoolSize,且等待队列未满,则进入等待队列 3.如果当前池大小poolSize大于corePoolSize且小于maximumPoolSize,且等待对列已满,则创建新线程执行任务。 4.如果当前池大小poolsize大于corePoolSize且大于maximumPoolSize,且等待队列已满,则调用拒绝策略来处理任务 5.线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列是否还有线程任务需要执行,如果在keepAliveTime里等不到新的任务了,那么线程就会退出。

转载请注明原文地址: https://www.6miu.com/read-63892.html

最新回复(0)