线程

线程和进程:

进程:

在操作系统中,每个独立运行的程序就是一个进程,当一个程序进入内存运行时,即变成一个进程。

进程是操作系统进行资源分配和调度的一个独立单位,进程之间资源不共享,多进程之间通过信号,管道进行交互。

线程:

是进程的组成部分,一个进程可以有多个线程,至少有一个。线程是最小的处理单位,可以拥有自己的堆栈,计数器,局部变量,但不能拥有系统资源,多线程之间数据块可以共享

java线程模型

java线程模型提供线程所必需的功能支持,基本的java线程模型有Thread类,Runnable接口,Callable接口和Future接口等。

Thread类

主要方法:

  • Thread构造方法,包含多个重载类型
  • getName()获取线程名称
  • setName()设置线程名称
  • isAlive() 判断线程是否处于激活状态,返回boolean值
  • getId()获取线程ID
  • setPriority()设置线程优先级
  • getPriority() 获取线程优先级
  • join()等待线程死亡
  • sleep()将线程挂起一段时间,以毫秒为单位
  • run()线程的执行方法
  • start()开始线程
  • stop()停止线程,已过期
  • interrput()中断线程
  • activeCount()返回激活的线程数

主线程

在java语言中,每个能够独立运行的Java程序都至少有一个主线程,且在程序启动时,JVM会自动创建一个主线程来执行该程序中的main()方法

在多线程编程时,main()方法的方法体就是主线程的执行体,main()方法中的代码就是主线程要完成的任务

创建线程

三种方法:

  • 继承Thread类,重写Thread类中的run()方法,直接创建线程
  • 实现Runnable接口,再通过Thread类和Runnable的实现类间接创建一个线程
  • 使用Callable和Future的接口间接创建线程

上述三种方式从本质上是一致的,最终都是通过Thread类来建立线程,提供接口是由与java不支持多继承,用这种方法还可以继承其他类。

1.继承Thread类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package 线程;

public class Thread1 extends Thread{
//重新run方法
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<=10;i++) {
System.out.println(this.getName()+" : "+i);
}
}
public static void main(String[] args) {
Thread1 thread1=new Thread1();
//启动线程
thread1.start();
//主线程任务
for(int i=1000;i<=1010;i++) {
System.out.println(Thread.currentThread().getName()+" : "+i);
}
}
}

结果如下:

继承Threadd类实现线程的结果

2.实现Runnable接口

Runnable接口中只有一个run()方法,一个类实现Runnable接口后,并不代表该类是个“线程类”,不能直接启动线程,必须通过Thread类的实例来创建并启动线程
步骤如下:

1 定义一个类实现Runnable接口,并实现run()方法
2 以实现类为参数创建一个Thread类的实例
3 调用Thread对象的start()方法启动线程

实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package 线程;
class MyThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
//使用Runnable接口时,只能使用Thread.currentThread()获取当前线程
for(int i=0;i<=10;i++)
System.out.println(Thread.currentThread().getName()+" : "+i);
}
}

public class Thread2 {

public static void main(String[] args) {
Thread thread=new Thread(new MyThread());
thread.start();
for(int i=1000;i<=1010;i++)
System.out.println(Thread.currentThread().getName()+" : "+i);
}
}

结果如下:

使用Runnable接口实现线程

3.使用Callable和Future接口

Callable接口提供一个call()方法作为线程的执行体,该方法的返回值使用Future接口来代表。使用Callable和Future接口的最大优势在于可以在线程执行完任务之后获取执行结果,步骤如下:

1 创建Callable接口的实现类,并实现call()方法,该方法将作为线程的执行体,并且有返回值;然后创建Callable实现类的实例
2 使用FutureTask类来包装Callable对象,在FutureTask对象中封装了Callable对象的call()方法的返回值
3 使用FutureTask对象作为Thread对象的target,创建并启动新线程
4 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package 线程;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//1.创建Callable接口的实现类
class Task implements Callable<Integer> {
int i = 0;

public Integer call() throws Exception {
// TODO Auto-generated method stub
for (; i <= 10; i++)
System.out.println(Thread.currentThread().getName() + " : " + i);
return i;
}
}

public class Thread3 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 2.使用FutureTask类包装Callable实现类的实例
FutureTask<Integer> task = new FutureTask<Integer>(new Task());
// 3.创建线程,使用FutureTask对象task作为Thread对象的Target,并调用start方法启动线程
new Thread(task, "子线程").start();
// 4.调用FutureTask对象task的get()方法获取子线程执行结束后的返回值
System.out.println("子线程返回值:" + task.get());
// 主线程任务
for (int i = 1000; i <= 1010; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
}
}

结果如下:

采用Callable和Future接口实现线程
从java8开始可以直接使用Lambda表达式创建Callable对象,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package 线程;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Thread4 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<Integer> task = new FutureTask<Integer>(
(Callable<Integer>)()->{
int i = 0;
for (; i <= 10; i++)
System.out.println(Thread.currentThread().getName() + " : " + i);
return i;
}
);
new Thread(task, "子线程").start();
System.out.println("子线程返回值:" + task.get());
// 主线程任务
for (int i = 1000; i <= 1010; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
}
}
}

运行结果同上


线程
https://shanhainanhua.github.io/2019/09/05/线程/
作者
wantong
发布于
2019年9月5日
许可协议