1.什么是进程
进程:在操作系统中运行的某个程序/软件
任何软件/程序要运行都要被加载到内存中,而内存负责运行这个软件/程序所有的内存空间,就被称为当前软件在内存中的一个进程。
进程需要依赖于操作系统。
进程就是操作系统中动态运行的静态代码。
2.什么是线程
线程就是操作系统中动态运行的静态代码【进程】中的某一项具体的功能的执行过程【执行轨迹/机型线索】。
例如:
我们在window操作系统上打开“暴风影音”播放电影,此时“暴风影音”就会在 window操作系统中产生一个进程;打开“暴风影音”播放电影的时候有画面,声音,中文字幕等等,这些画面,声音,中文字幕就是这个“暴风影音”进程中的多个线程。
3.什么是多线程?
多线程:某一个程序在运行的时候可能会产生多个不同的执行线索【执行轨迹】,这些多个不同的执行线索【执行轨迹】共同运行的情况就是多线程。
往往我们会感觉到这些多个不同的执行线索【执行轨迹】同时执行,实际上这是一种错觉,实际上当这些不同的线索【执行轨迹】在运行的时候,某一个时刻只有一个线索【执行轨迹】在运行,只是这么多的不同的执行线索【执行轨迹】快速的切换。
4.为什么使用多线程?
1)使用多线程的目的就是为了提高程序的执行效率。
2)解决并发问题。
并行和并发的区别
并行:多个处理器或者多核处理器同时处理多个任务。
并发:多个任务在同一个cpu核上,按细分的时间片轮流(交替)执行,从逻辑上开来那些任务在同时执行。
5.多线程的创建方式和区别
1)通过继承Thread类创建线程类
Thread类java提供的创建线程的线程类。
创建步骤
1.创建一个类,继承Thread类
2.重新run()方法
3.将需要由线程执行的代码放在run()方法中。
例子:
//继承Thread线程类。
class MyThread extends Thread{
@Override
public void run() {
// 需要在线程中处理的代码
String threadname = Thread.currentThread().getName();
for (int i = 0; i <= 50; i++) {
System.out.println(threadname + "-i --" + i);
}
}
}
运行步骤
1.创建线程子类对象
2.通过线程对象调用start方法启动线程
例子:
// 创建线程对象,执行线程
MyThread my = new MyThread();
MyThread my2 = new MyThread();
my.start();
my2.start();
2)通过实现Runnable借口创建线程类
Runnable接口
(1)Thread类实现过这个借口。
(2)只有一个run方法。
创建的步骤
1. 创建类,实现Runnable借口。
2. 重写run方法。
3. 将需要在线程中执行的代码放在run方法体中。
运行步骤
1.创建目标对象(实现Runnable的类)。
2.通过Thread类的构造函数将目标对象转换成线程对象。
3.通过线程对象的start方法启动线程。
3)通过Callable和Future借口创建线程
java.util.concurrent.Callable接口:这个接口只有一个call()方法。
java.util.concurrent.Future接口:有一个重要的方法get()
实用方法
1.public boolean cancel(boolean mayInterruptlfRunning)
: 是否取消正在执行的线程任务[false为取消任务]
2.public boolean isCancelled()判断是否是线程任务没有运行结束之前取消线程。
3.public boolean isDone()判断线程任务是否正常执行完毕
4.V get()得到线程任务的执行结果
创建的步骤
1.创建一个类,实现Callback接口
2.重写call();
3.将需要有线程执行的代码卸载call方法中
注意:实现Callable接口的时候需要指定线程执行结果的返回值类型。
例子:
//1.实现Callable接口
class Targetsrc implements Callable<Integer>{
@Override
//重写call方法
public Integer call() throws Exception {
// TODO Auto-generated method stub
int i;
String name = Thread.currentThread().getName();
for (i = 1; i < 51; i++) {
System.out.println(name + " i = " + i);
}
return i;
}
}
运行的步骤:
1.创建目标对象
2.通过FutureTask类的构造方法public FutureTask(Callable<V>callable)封装目标对象成Runnable子类对象。
3.通过Thread类的构造方法public Thread(Runnable rounnable)创建线程对象。
例子:
// 2.创建对象在主类
//目标对象
Targetsrc srcf = new Targetsrc();
FutureTask<Integer> task = new FutureTask<>(srcf);
FutureTask<Integer> task2 = new FutureTask<>(srcf);
Thread f2 = new Thread(task);
Thread f1 = new Thread(task2);
f2.start();
f1.start();
//task.cancel(false);//false是关闭
//由于先关闭,所以无法获取
int i = task.get();
System.out.println("***********:" + i);
第四种,通过线程池创建多线程【使用的比较少,所以不强调】
比较复杂
4)多线程的区别
继承Thread类 | 实现Runnable接口 | Callable和Future接口 |
创建新类继承Tread类重写run方法 | 创建新类实现Runnable接口重写run方法 | 创建新类实现Callable接口重写call方法,注意Callable接口的泛型类型 |
run方法没有返回值,不能声明抛异常 | call方法有返回值,通过Future接口提供的get方法的到返回值,可以声明抛出异常 | |
创建Thread类的子对象[线程对象],通过子类对象调用start方法启动线程对象 | 创建实现Runnable接口的子类对象【目标对象】,通过Thread的构造方法将目标对象转换成线程对象,通过线程对象调用start方法启动线程 | 创建实现Callable接口的子类「目标对象」,通过Future接口的子类FutureTask类将Callable接口的子类将Runnable接口类型,通过Thread的构造方法将目标对象转换成线程对象,通过线程对象的start方法启动线程 |
无法资源共享 | 可以资源共享 | 可以考虑资源共享 |
不考虑资源共享时使用 | 考虑资源共享时使用 | 考虑资源共享、异步编程。 |
无奈源于不够强大