多线程的目的
为了更合理的利用cpu资源
多线程的概念
一个进程(内存中运行的一个应用程序)运行时产生多个线程,进程拥有独立的内存空间,而一个进程内的线程共享一个内存空间。线程之间可以自由切换,并发执行。
并行与并发
并行:多个cpu实例同时执行一段逻辑
并发:通过cpu调度算法,让程序看上去像是同时执行,提高程序运行效率。
多线程的实现方式
- 通过创建的对象继承Thread类,调用start()方法启动run()方法里面的任务。
- 通过实现Runnable接口,调用run()方法启动任务。
//Runnable接口
public interface Runnable {
public abstract void run();
}
- 通过实现Callable接口,调用run()方法启动任务。
//Callable接口
public interface Callable<V> {
V call() throws Exception;
}
1. 编写类实现Callable接口 , 实现call方法
class XXX implements Callable<T> {
@Override
public <T> call() throws Exception {
return T;
}
}
2. 创建FutureTask对象 , 并传入第一步编写的Callable类对象
FutureTask<Integer> future = new FutureTask<>(callable);
3. 通过Thread,启动线程
new Thread(future).start()
1 vs 2:
a. [2]通过创建任务给线程分配的方式实现多线程,适合多线程执行相同任务。
b. Java 允许单继承,多实现,[1]的对象可以实现多个接口并且也可以继承其他类,避免单继承所造成的局限。
c. 任务与线程本身分离,程序更健壮。
d.线程池技术不接受Thread类型的线程对象,接受Runnable的任务。
e.[1]通过匿名内部类的方式可以做到简单实现多线程不用单独创建类。
2 vs 3:
a. [2] 没有返回值,[3]可以通过FutureTask.get()返回执行结果,虽然会阻塞主进程继续往下执行。
b. [2]的run()方法不能抛出异常,[3]的call()方法可以抛出异常。
线程安全
线程安全:在并发的前提下,该代码经过多线程的使用,线程的调度顺序不影响产生的结果。
线程不安全:与线程安全相反,线程的调度顺序影响最终的结果
同步:通过人为的控制与调度,保证共享资源的多线程访问成为线程安全,确保结果的准确。
调度:1.分时 2.抢占
分时调度:所有线程轮流使用cpu,平均分配每个线程的占用时间
抢占式调