线程和进程:
进程:
在操作系统中,每个独立运行的程序就是一个进程,当一个程序进入内存运行时,即变成一个进程。
进程是操作系统进行资源分配和调度的一个独立单位,进程之间资源不共享,多进程之间通过信号,管道进行交互。
线程:
是进程的组成部分,一个进程可以有多个线程,至少有一个。线程是最小的处理单位,可以拥有自己的堆栈,计数器,局部变量,但不能拥有系统资源,多线程之间数据块可以共享
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{ @Override public void run() { 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); } } }
|
结果如下:
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() { 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); } }
|
结果如下:
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;
class Task implements Callable<Integer> { int i = 0;
public Integer call() throws Exception { 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 { FutureTask<Integer> task = new FutureTask<Integer>(new Task()); new Thread(task, "子线程").start(); System.out.println("子线程返回值:" + task.get()); for (int i = 1000; i <= 1010; i++) { System.out.println(Thread.currentThread().getName() + " : " + i); } }
|
结果如下:
从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); } } }
|
运行结果同上