多线程
线程是一个程序内部的一条执行流程
多线程:指从软硬件上实现的多条执行流程的技术
创建多线程
Java通过java.lang.Thread类的对象来代表线程
创建的三种方式
- 自定义线程类继承Thread类,并且其中要重写Thread类中的run方法(run方法用来描述线程的执行任务),接着在程序中创建线程类的对象,最后使用start方法执行线程就可以。(Tips:main方法本质也是一条默认的主线程来执行,start执行后就多了一个线程)
优点:编码简单
缺点:线程类已经继承Thread类后,无法再继承其他类,不利于功能扩展(Java单继承) - 自定义任务类实现Runnable接口,并且重写Runnable中的run方法(run方法用来描述线程的执行任务),接着在主程序中创建任务类的对象,然后将任务对象交给一个线程对象处理(new Thread(**)),最后调用线程对象的start方法。
优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强。
缺点:需要多一个Runnable对象(无伤大雅) - 由于上面两种方式在线程执行结束后没办法返回数据,JDK5.0提供了Callable接口和FutureTask类来实现,可以直接返回线程执行完毕的结果。首先自定义一个类实现Callable接口,并且重写call方法(用来描述线程的执行任务和要返回的数据),接着将Callable类型的对象封装成FutureTask(线程任务对象,实现了Runnable接口),然后将线程对象交给Thread对象,最后调用Thread对象的start方法启动线程。通过FutureTask调用get方法可以获取返回结果
优点:线程任务只是接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取执行结果
缺点:编码较复杂
相关方法
注意事项
- 启动线程是调用start方法,而不是run方法
- 不要把主线程任务放在启动子线程之前
线程安全
什么是线程安全问题:多个线程,同时操作一个共享资源的时候,可能会出现业务问题
线程同步
解决线程安全问题的方案,让多个线程实现先后依次访问共享资源
解决方案
加锁
每次仅允许一个线程加锁,加锁后才可以进入互斥区访问,访问完毕后自动解锁,其他线程再加锁进入
加锁方法
-
同步代码块:将访问共享资源的核心代码上锁。注意事项:对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象),否则会出bug。
写法:将互斥区放在synchronized(){}并且在其中加入一个唯一对象,如this,synchronized(this){},不同的项目要求有不同的锁,若是对于静态代码段还可以用class文件,因为全局唯一。对于实例方法建议使用this -
同步方法:把访问共享资源的核心方法给上锁
-
Lock锁:自己创建锁对象,Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。但是更灵活,使用与计网中的互斥操作相同。
Tips:最好使用try-finally,并且将unlock放在finally中,避免执行代码时出错,锁无法释放。
线程通信
当多个线程共同操作共享的资源时,线程间通过某种方式互相告知自己的状态,以相互协调,并避免无效的资源争夺。
要使用当前同步锁对象来进行调用这些方法,先唤醒后等待
线程池
复用线程技术。
提交的任务对象要实现Runnable或者Callable接口。
创建线程池
JDK5.0开始提供了代表线程池的接口:ExecutorService,常用实现类:ThreadPoolExecutor
- 方法一:使用ThreadPoolExecutor自创建一个线程池对象
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/6a4e55a140de4c8a8232cec38ccad7f6.png
参数要背,面试考题
- 方法二:使用Executors(线程池的工具类)
Executors是一个线程池的工具类,提供了很多静态方法用于返回不同的线程池对象
这些方法的底层都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象
线程池处理Runnable任务/Callable任务
线程的生命周期
Tips:sleep不释放锁
悲观锁和乐观锁
悲观锁:一上来就加锁,没有安全感,每次只可以一个线程进入,访问完毕后再解锁。线程安全,性能较差。
乐观锁:一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制,线程安全,性能较好。(例子:在多个线程进行整数修改的时候,记录取数时的原始值,再修改完整数填入变量前,查看原始值是否已经被其他线程修改,若修改就代表出现了线程安全问题则此次操作作废,重新取值计算,接着重复上述,若原始值不变就代表没有线程安全问题,直接填入。)
乐观锁的种类
- 整数修改的乐观锁,原子类实现。CAS(比较和修改)算法