• 多线程(待补充)


    一、多线程

    1、程序:为了完成特定的任务用魔种语言编写的一种指令的集合,即指一段静态的静态对象。

    2、进程:程序执行的一次过程,或者正在运行的一个程序是一个动态的过程:产生 -> 存在 -> 消亡 进程是资源分配的单位,徐通在运行是为每个进程分配不同的内存区域

    3、进程:

    (1)进程进一步细化为线程,是程序内部执行的一条路径

    (2)若一个进程同时执行多个线程,就是执行多线程

    (3)线程作为一个执行和调度的单位,每个线程拥有独立的运行栈和计数器,线程的切换开销比较小,方法区和堆内存被该进程的所有线程共享。


    4、并行:多个CPU同时执行多个任务

    5、并发:一个CPU(时间片)同时执行多个任务,多个任务之间切换。实际应用场景:秒杀

    6、使用多线程的优点:提高应用程序的响应效率,对于图形化界面的意义重大,变相的提高了用户的体验,提高CPU的利用率,优化程序的结构,可以把复杂冗长的进程分为多个线程,提高CPU的利用率,优化程序的结构,可以把复杂冗长的进程分为多个线程,每个线程独立运行。降低耦合度,便于修改

    7、使用多线程的时机:需要同时完成多个任务,文件的读写操作,网络的操作,搜索,需要后台运行的时候。

    8、一个java程序运行至少需要3个线程,一个是main()主线程,gc()线程,异常处理线程,线程的创建和使用:4种方法(jdk1.5之前只有前两种)


    二、实现多线程的方法

    1、方法一:

    (1)继承Thread类

    (2)重写run方法

    (3)创建子类对象

    (4)调用对象的start()方法

    2、方法二:

    (1)实现Runnable接口

    (2)实现run方法

    (3)创建实现类对象放入Thread对象种

    (4)调用Thread对象的start()方法,静态代理中,实现Runable:

    3、继承Thread类:线程代码是存放在Thread子类run方法;实现Runable:线程代码存在实现类的run方法中。

    4、推荐使用实现的方式:

    (1)可以避免单继承的局限性。

    (2)多个线程共享同一接口实现类的对象,适合多个相同线程处理共享资源。

    5、Thread类中的常用方法

    (1)void start() 启动线程,并执行对象的run方法

    (2)void run() 线程在被调度的时执行的方法。

    (3)String getName() 返回线程的名字

    (4)setName() 设置线程的名字

    (5)static Thread currentThread() 返回当前线程对象

    (6)static void yield() 线程让步(把执行权交给优先级更高的线程),会暂停当前正在执行的线程,把执行权交给相优先级、或者高优先级的线程。

    交出CPU的执行权后,CPU依旧可能会分配给它执行权。

    (7)join() 当前线程调用了join方法,那么当前线程会被阻塞,转而执行join所加进来的线程,直到加入进来的线程执行完毕才会继续指向当前线程

    (8)static void sleep() 当前线程休眠指定的毫秒数。

    (9)setPriority() 设置线程优先级,最小1、最大10、默认5。

    (10)getPriority() 获取优先级,低优先级的线程获得调度的概率不为0,只是有点小

    通过继承的方式常见线程,优先级等于父类

    (11)在java中线程分为:用户线程和守护线程(通过jvm何时离开进行划分),守护线程是为了用户线程服务的。可以在strat之前调用线程的deamon(true)设置用户线程为守护线程

    三、线程的生命周期

    1、时间片;抢占式:高优先级的线程抢占CPU

    2、生命周期:

    (1)新建:当Tread类或者其子类被声明创建的时候,新生的线程对象处于新建状态

    (2)就绪:新建线程调用了start方法,进入到线程队列,等待CPU的时间片,此时已经具备了运行条件,只是没有获得CPU执行权。

    (3)运行:就绪的线程获得CPU的资源,并被调度,进入运行状态

    (4)阻塞:将线程被动挂起,将CPU临时终止了线程执行,进入阻塞状态

    (5)消亡:被人为的停止、执行完成或出现异常没有处理之后,线程消亡。


    四、线程的同步

    1、解决线程安全的问题

    (1)使用synchronized同步代块

    synchronized(Object 同步监听器){

    操作共享的代码

    }

    (2)同步监听器:数可以使用任意对象充当,可以是Object类型

    2、解决线程安全的方法:

    (1)将共享

    (3)可以通过反射获取到线程类的对象:线程类.class

    3、同步代码块包裹的必须是操作供选个数据的代码,范围不能太大,否则体现不出多线程的功能;范围太小可能锁不住共享数据

    4、解决线程安全问题的第二种方式:

    使用同步方法:public synchronized void salaTicket(){};默认获取的同步监听器为this

    5、不管使用哪种方法,都要保证同步监听器的唯一

    6、一个线程类种的所有静态方法共用同一把锁(类名.class),非静态方法公共的同一把锁(this)。

    7、释放锁操作:

    (1)同步方法或者同步代码块中return 和 break释放锁操作;

    (2)yeild()、sleep()不会释放锁;

    (3)执行完同步方法或者同步代码也会释放锁

    (4)当前进程同步代码块或者同步方法调用了wait()方法,当前线程阻塞,并且释放锁

    (5)当前线程同步方法调用了supend()方法,将线程挂起,不会释放锁。(尽量不要使用supend()方法,与之相对应的还有一个resume()方法,用来放下挂起的状态)

    8、单例模式

    懒汉式的线程安全:懒汉式需要构造方法私有化

    9、死锁:不同的线程分别占用了对方所需要的同步资源不放弃。都在等待对方先放弃同步资源,最终形成了死锁;出现死锁之后不会异常、不会出现提示,所有的线程都处于阻塞状态。

    10、解决死锁:尽量避免同步嵌套;尽量减少同步资源的定义;

    11、Lock显示锁:接口,和synchronized拥有箱体哦那个的并发性和内存语义。

    Lock lock = ...//通常是ReentrantLock对象(是Lock的一个子类)

    lock.lock();

    try{

    共享资源

    }finally{

    lock.unlock();

    }

    12、synchronized和Lock对比:

    (1)Lock是显示锁:可以手动的开启和关闭锁;synchronized是隐式锁:出了作用域自动释放。

    (2)Lock是代码块锁;synchronized有代码块锁和方法所。

    (3)JVM中:使用Lock花费的调度线程时间较少,性能更好,扩展性较高。优先使用:Lock-->同步代码块-->同步方法

    五、线程的通信

    (1)基本思路:进程一种进入等待后,唤醒正在等待的进程二(通过wait()和notify()),同理,进程二进入等待后唤醒正在等待的进程一。

    (2)wait():让当前进程挂起,并放弃CPU,同步资源并等待,使别的线程可以访问并修改共享资源,只有其他线程在获取锁之后,调用notify()或者notifyAll()该线程才能被唤醒,并重新排队。

    (3)notify():唤醒正在等待同步资源的线程中优先级最高者。

    (4)notifyAll():唤醒正在排队等待同步资源的所有线程。

    (5)notify和wait只能用在同步方法中


    六、线程池

    1、非阻塞队列:当队满,入队,数据丢失;对空,出队,得到null

    2、阻塞队列:当队满,入队,进行队列,直到出队操作执行之后再入队;出队,等待,当队中有元素之后再出队

    LinkedBlockingDeque

    3、线程池用的是阻塞队列

    4、线程池:节省了线程创建和销毁的时间,线程池中的线程无需创建和销毁,可以直接拿来使用


    5、ThreadPoolExecutor(核心线程数,最大线程数,时间,时间单位TimeUnit,阻塞队列)

    6、线程池的分类

    (1)可缓存:ExutorService es = Excutors.newCachedThreadPool();

    (2)定长:ExutorService = Excutors.newFixedThreadPool(3) //核心线程数固定

    (4)定时:ExutorService = Excutors.newScheduleThreadPool(3)

    (5)单例:ExutorService = Excutors.newSingleThreadPool

    七、Callable

    1、步骤:

    (1)实现Cakkable接口

    (2)实现call方法

    (3)借助FutureTask类

    (4)启动线程(FutureTask是Runnable的实现类)

    (5)FutureTask类对象的get()方法,方法回调取得call()的返回值

    2、对比:相对于run方法 call方法是可以有返回值的,是可以抛异常的、支持泛型 但是需要借助FutureTask类,比如说获取方法返回值

  • 相关阅读:
    django djangorestframework的简单使用
    html element截图,无需服务端即可下载的功能
    iOS 三种路由对比(TargetAction,Protocol, URL)
    技术网站集合
    【转】windows 没有hyperv 解决方法
    Vue.js基本使用
    yml 配置数据库的多数据源配置,@DS注解 ,dynamic
    vue 兼容ie 下载图片
    ie兼容 justifycontent: spaceevenly
    TrueNAS存储池简介
  • 原文地址:https://www.cnblogs.com/JQbiu/p/11248185.html
Copyright © 2020-2023  润新知