初入多线程

本文详细介绍了Java中多线程的实现方式,包括自定义Thread类、实现Runnable接口和Callable接口,以及如何使用线程同步、锁机制(悲观锁和乐观锁)保证线程安全。还涵盖了线程池的创建和使用,以及线程的生命周期管理。
摘要由CSDN通过智能技术生成

多线程

线程是一个程序内部的一条执行流程
多线程:指从软硬件上实现的多条执行流程的技术

创建多线程

Java通过java.lang.Thread类的对象来代表线程

创建的三种方式

  1. 自定义线程类继承Thread类,并且其中要重写Thread类中的run方法(run方法用来描述线程的执行任务),接着在程序中创建线程类的对象,最后使用start方法执行线程就可以。(Tips:main方法本质也是一条默认的主线程来执行,start执行后就多了一个线程)
    优点:编码简单
    缺点:线程类已经继承Thread类后,无法再继承其他类,不利于功能扩展(Java单继承)
  2. 自定义任务类实现Runnable接口,并且重写Runnable中的run方法(run方法用来描述线程的执行任务),接着在主程序中创建任务类的对象,然后将任务对象交给一个线程对象处理(new Thread(**)),最后调用线程对象的start方法。
    优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强。
    缺点:需要多一个Runnable对象(无伤大雅)
  3. 由于上面两种方式在线程执行结束后没办法返回数据,JDK5.0提供了Callable接口和FutureTask类来实现,可以直接返回线程执行完毕的结果。首先自定义一个类实现Callable接口,并且重写call方法(用来描述线程的执行任务和要返回的数据),接着将Callable类型的对象封装成FutureTask(线程任务对象,实现了Runnable接口),然后将线程对象交给Thread对象,最后调用Thread对象的start方法启动线程。通过FutureTask调用get方法可以获取返回结果
    优点:线程任务只是接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取执行结果
    缺点:编码较复杂

相关方法
在这里插入图片描述

注意事项

  1. 启动线程是调用start方法,而不是run方法
  2. 不要把主线程任务放在启动子线程之前

线程安全

什么是线程安全问题:多个线程,同时操作一个共享资源的时候,可能会出现业务问题

线程同步

解决线程安全问题的方案,让多个线程实现先后依次访问共享资源

解决方案

加锁

每次仅允许一个线程加锁,加锁后才可以进入互斥区访问,访问完毕后自动解锁,其他线程再加锁进入
加锁方法

  1. 同步代码块:将访问共享资源的核心代码上锁。注意事项:对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象),否则会出bug。
    写法:将互斥区放在synchronized(){}并且在其中加入一个唯一对象,如this,synchronized(this){},不同的项目要求有不同的锁,若是对于静态代码段还可以用class文件,因为全局唯一。对于实例方法建议使用this

  2. 同步方法:把访问共享资源的核心方法给上锁
    在这里插入图片描述

  3. Lock锁:自己创建锁对象,Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。但是更灵活,使用与计网中的互斥操作相同。
    在这里插入图片描述
    Tips:最好使用try-finally,并且将unlock放在finally中,避免执行代码时出错,锁无法释放。

线程通信

当多个线程共同操作共享的资源时,线程间通过某种方式互相告知自己的状态,以相互协调,并避免无效的资源争夺。
在这里插入图片描述要使用当前同步锁对象来进行调用这些方法,先唤醒后等待

线程池

复用线程技术。
提交的任务对象要实现Runnable或者Callable接口。

创建线程池

JDK5.0开始提供了代表线程池的接口:ExecutorService,常用实现类:ThreadPoolExecutor

  1. 方法一:使用ThreadPoolExecutor自创建一个线程池对象
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/6a4e55a140de4c8a8232cec38ccad7f6.png在这里插入图片描述在这里插入图片描述

参数要背,面试考题

  1. 方法二:使用Executors(线程池的工具类)
    Executors是一个线程池的工具类,提供了很多静态方法用于返回不同的线程池对象在这里插入图片描述
    这些方法的底层都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象
    在这里插入图片描述

线程池处理Runnable任务/Callable任务

在这里插入图片描述
在这里插入图片描述

线程的生命周期

在这里插入图片描述

在这里插入图片描述Tips:sleep不释放锁

悲观锁和乐观锁

悲观锁:一上来就加锁,没有安全感,每次只可以一个线程进入,访问完毕后再解锁。线程安全,性能较差。
乐观锁:一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制,线程安全,性能较好。(例子:在多个线程进行整数修改的时候,记录取数时的原始值,再修改完整数填入变量前,查看原始值是否已经被其他线程修改,若修改就代表出现了线程安全问题则此次操作作废,重新取值计算,接着重复上述,若原始值不变就代表没有线程安全问题,直接填入。)
乐观锁的种类

  1. 整数修改的乐观锁,原子类实现。CAS(比较和修改)算法
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值