1.进程定义
在操作系统中运行的某个软件或者某个程序。
任何软件或者程序要运行都要被加载到内存中,而内存负责运行这个软件或程序所需要的那些内存空间,就被称为当前软件在内存中的一个进程。
进程需要依赖于操作系统,是在操作系统中动态运行的静态代码。
2.线程定义
线程就是在操作系统中动态运行的静态代码【进程】中的某一项具体功能的执行过程【执行轨迹/执行线索】。
比如我们在window操作系统上打开“暴风影音”播放电影,此时“暴风影音”就会在window操作系统中产生一个进程;打开“暴风影音”播放电影的时候有画面,声音,中文字幕等等,这些画面,声音,中文字幕就是这个“暴风影音”进程中的多个线程。
3.多线程定义
某一个程序在运行的时候可能会产生多个不同的执行线索【执行轨迹】,这些多个不同的执行线索【执行轨迹】共同运行的情况就是多线程。
往往我们会感觉到这些多个不同的执行线索【执行轨迹】同时执行,实际上这时一种错觉假象,实际上当这些多个不同的执行线索【执行轨迹】在运行的时候,某一个时刻只有一个执行线索【执行轨迹】在运行,只是这多个不同的执行线索【执行轨迹】快速的切换而已。
4.多线程作用
(1)使用多线程的目的就是为了提高程序的执行效率。
(2)解决并发问题。
并行和并发区别 | |
并行 | 多个处理器或多核处理器同时处理多个任务 |
并发 | 多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行 |
5.多线程的创建方式【4种】
5.1通过继承Thread类创建线程类
5.1.1 创建步骤
1.创建一个类,继承Thread类;
2.重写run方法;
3.将需要由线程执行的具体动作写入run方法
例:
public class MyThread extends Thread{
public void run() {
for(int i=1;i<=50;i++){
//得到当前正在运行的线程对象的名称
String name = Thread.currentThread().getName();
System.out.println(name+"---i=="+i);
}
}
}
5.1.2 运行步骤
1.创建线程类的对象;
2.通过线程对象调用start方法启动线程。
start方法只负责启动线程,启动后具体运行怎么走由操作系统决定。
例:
public class MyThreadMain {
public static void main(String[] args) {
//创建线程类的对象
MyThread mythread1=new MyThread();//线程1
MyThread mythread2=new MyThread();//线程2
//通过线程对象调用start方法启动线程
mythread1.start();
mythread2.start();
}
}
每次运行的结果是不一样的。
5.2 通过实现Runnable接口创建线程类
Runnable接口--Thread类就实现过这个接口
Runnable接口里只有一个run方法。
5.2.1 创建步骤
1.创建一个类,实现Runnable接口;
2.重写run方法;
3.将需要由线程执行的具体动作写入run方法。
例:
public class MyThread implements Runnable{
public void run() {
for(int i=1;i<=10;i++){
//得到当前正在运行的线程对象的名称
String name = Thread.currentThread().getName();
System.out.println(name+"---i=="+i);
}
}
}
5.2.2 运行步骤
1.创建目标对象
2.通过Thread类的构造方法创建线程对象
3.通过线程对象调用start方法启动线程
例:
public class MyThreadMain {
public static void main(String[] args) {
//启动线程要用start方法,而start方法是Thread类的方法,Runnable接口里面没有
//Runnable接口只有一个run方法
//因此直接new MyThread 是调用不了start方法的
//所以需要用到Thread类的构造方法public Thread(Runnable target)
//当一个方法的参数是接口类型的时候,可以传递子类对象,因此把MyThread对象传进去
MyThread myThread = new MyThread();//创建目标对象
Thread th1=new Thread(myThread);//创建线程对象
Thread th2=new Thread(myThread);
th1.start();
th2.start();
}
}
5.3 通过Callable和Future接口创建线程
java.util.concurrent.Callable接口--这个接口中只有一个方法call();
java.util.concurrent.Future接口--有一个重要方法get() ;
1. public boolean cancel(boolean mayInterruptIfRunning)是否取消正在执行的线程任务【false为取消任务】
2. public boolean isCancelled()判断是否是线程任务没有运行结束之前取消线程
3. public boolean isDone()判断线程任务是否正常执行完毕
4. V get()得到线程任务的执行结果
java.util.concurrent.FutureTask类--继承了Runnable接口。
1. public boolean cancel(boolean mayInterruptIfRunning)是否取消正在执行的线程任务【false为取消任务】
2. public boolean isCancelled()判断是否是线程任务没有运行结束之前取消线程
3. public boolean isDone()判断线程任务是否正常执行完毕
4. V get()得到线程任务的执行结果
Future接口和FutureTask类都有上面四个方法,因为FutureTask实现了RunnableFuture,RunnableFuture继承了Runnable, Future。
5.1.1 创建步骤
1.创建一个类,实现Callable接口
2.重写call();
3.将需要由线程执行的具体动作写入call()方法
注意:实现Callable接口的时候需要指定线程执行结果的返回值类型
例:
import java.util.concurrent.Callable;
//创建一个类,实现Callable接口,<>返回值
public class MyThread implements Callable<Integer>{
public Integer call() throws Exception {
int i=1;
while(i<=10){
String name=Thread.currentThread().getName();
System.out.println(name+"----i=="+i);
i++;
}
return i;
}
}
5.1.2 运行步骤
1.创建目标对象
2.通过FutureTask类的构造方法public FutureTask(Callable<V> callable)封装目标对象成Runnable子类对象
3.通过Thread类的构造方法public Thread(Runnable runnable)创建线程对象
例:
import java.util.concurrent.FutureTask;
public class MyThreadMain {
public static void main(String[] args) {
//创建目标对象
MyThread myThread = new MyThread();
//通过FutureTask类的构造方法public FutureTask(Callable<V> callable)封装目标对象成Runnable子类对象
FutureTask futuretask1=new FutureTask(myThread);
FutureTask futuretask2=new FutureTask(myThread);
//通过Thread类的构造方法public Thread(Runnable runnable)创建线程对象
Thread thread1=new Thread(futuretask1);
Thread thread2=new Thread(futuretask2);
//启动线程
thread1.start();
thread2.start();
}
}
5.4 通过线程池创建多线程
使用的比较少,里面的东西有些还没学到,暂时不处理学习。
6.多线程创建方式的区别***
继承Thread类 | 实现Runnable接口 | Callable和Future接口 |
创建新类继承Thread类重写run方法 | 创建新类实现Runnable接口重写run方法 | 创建新类实现Callable接口重写call方法,注意Callable接口的泛型类型 |
run 方法没有返回值,没有声明抛出异常 | call方法有返回值,通过Future接口提供的get方法得到返回值,可以声明抛出异常 | |
创建Thread类的子类对象【线程对象】,通过子类对象调用start方法启动线程 | 创建实现Runnable接口的子类对象【目标对象】,通过Thread类的构造方法传递参数,关联目标对象,创建线程对象【Thread类的对象】,通过线程对象调用start方法启动线程 | 创建实现Callable接口的子类对象【目标对象】,通过Future接口的子类FutureTask将目标对象包装成Runnable接口的子类对象,通过Thread类的构造方法,关联包装后的Runnable接口的子类对象,创建Thread类对象【线程对象】,通过线程对象调用start方法启动线程 |
无法资源共享 | 可以资源共享 | 可以资源共享 |
不考虑资源共享时采用 | 考虑资源共享时采用 | 考虑资源共享时采用 |
资源共享意思是不共用一个目标对象,比如卖5张票,线程1和2都会取卖着5张票,但没有共用5,导致线程1买了5张,线程2卖了5张,最后成了卖出10张票。
例:
public class MyThread extends Thread {
private int piao = 5;
public void run() {
boolean flag=true;
while(flag){
if(piao<=0){
flag=false;
}else{
String name=Thread.currentThread().getName();
System.out.println(name+",卖出1张票,还剩"+(--piao)+"票");
}
}
}
}
public class MyThreadMain {
public static void main(String[] args) {
//创建线程类的对象
MyThread mythread1=new MyThread();//线程1
MyThread mythread2=new MyThread();//线程2
//通过线程对象调用start方法启动线程
mythread1.start();
mythread2.start();
}
}
此处涉及线程同步问题,下一个文章再说
使用实现Runnable接口方法会资源共享