@TOC
线程简介
进程与线程
进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。
线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
简单来说:
进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程——资源分配的最小单位。
线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。线程——程序执行的最小单位。
并发
当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。
因此,多个线程时轮询执行的。
线程状态
线程可以分为五种状态:
- New 新建
- Runnable 就绪
- Running 运行
- Blocked 阻塞
- Dead 死亡
线程生命周期
- 新建
new Thread()
线程类 :Thread 类 和 Thread子类 - 就绪
调用了 start() 方法会进入到 就绪状态,等待cpu的调用执行; - 运行
处于就绪状态的 线程 被cpu调用执行了,就处于了运行状态。 - 阻塞
处于运行状态的线程由于某些原因暂停了 cpu的调用执行。- sleep:
sleep(毫秒时间) 等待
当线程A 调用了sleep方法,那么线程A处于阻塞状态,当阻塞的时间到了,那么 恢复到就绪状态,cpu调用执行。 - join:
join() :让其它线程先执行。
线程A 中 调用了 线程B的join方法,那么线程A需要等待线程B执行完,再执行,线程A再等待线程B执行的过程中 就 处于了阻塞状态,当线程B执行完毕了,线程A恢复到就绪状态,cpu调用执行。 - 同步
- wait()
- sleep:
- 死亡
线程正常 或 异常结束。
线程实现
主线程:程序启动后,最先 启动的一个线程。
主线程任务 在 main()中
是启动其它线程的线程。
public static void main(String[] args) {
// 获得当前正在运行的线程
System.out.println(Thread.currentThread());// Thread[main,5,main]
System.out.println(Thread.currentThread().getName());// 名字
}
子线程
创建子线程有三种方式:
- 继承Thread类
子线程 默认的名字: Thread-N (N表示第几个线程)
class StudentThread extends Thread{
public StudentThread(String name){
super(name);
}
@Override
public void run() {
for(int i = 0;i < 5; i++)
System.out.println(Thread.currentThread() + ":" + i);
}
}
public class TestThread {
public static void main(String[] args) {
StudentThread stThread = new StudentThread("Tom");
stThread.start();
}
}
输出:
Thread[Tom,5,main]:0
Thread[Tom,5,main]:1
Thread[Tom,5,main]:2
Thread[Tom,5,main]:3
Thread[Tom,5,main]:4
- 实现Runnable接口(一般使用这种方式)
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
class StudentThread implements Runnable{
@Override
public void run() {
for(int i = 0;i < 5; i++)
System.out.println(Thread.currentThread() + ":" + i);
}
}
public class TestThread {
public static void main(String[] args) {
// 不是线程类的对象
StudentThread studentThread = new StudentThread();
// 新建线程
Thread thread = new Thread(studentThread,"st");
thread.start();
}
}
输出:
Thread[st,5,main]:0
Thread[st,5,main]:1
Thread[st,5,main]:2
Thread[st,5,main]:3
Thread[st,5,main]:4
- 实现 Callable接口
@FunctionalInterface
public interface Callable<V> { // V 是返回值类型
V call() throws Exception;
}
class StudentThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for(int i = 0; i < 5; sum+=i,i++)
System.out.println(Thread.currentThread() + " " + i);
return sum;
}
}
public class TestThread {
public static void main(String[] args) throws InterruptedException, ExecutionException {
StudentThread studentThread = new StudentThread();
//用来得到返回值
FutureTask<Integer> futureTask = new FutureTask<>(studentThread);
Thread thread = new Thread(futureTask,"st");
thread.start();
System.out.println(futureTask.get());
}
}
输出:
Thread[st,5,main] 0
Thread[st,5,main] 1
Thread[st,5,main] 2
Thread[st,5,main] 3
Thread[st,5,main] 4
10
三种实现方式的比较
- 不利于资源的共享:
继承Thread类. - 实现资源的共享:
实现Runnale接口
实现Callable接口
实现Runnable接口 | 实现Callable接口 |
---|---|
run() | call() |
不能抛异常 | 可以抛异常 |
没有返回值 | 有返回值,通过方法来获得返回值,也可以知道线程运行的状态。 |
多线程实现
class OneThread implements Runnable{
@Override
public void run() {
for(int i = 0;i < 5;i++)
System.out.println(Thread.currentThread() + ":" + i);
}
}
public class TestMoreThread {
public static void main(String[] args) {
OneThread oneThread = new OneThread();
Thread first = new Thread(oneThread,"first");
Thread second = new Thread(oneThread,"second");
first.start();
second.start();
}
}
输出:
Thread[second,5,main]:0
Thread[first,5,main]:0
Thread[first,5,main]:1
Thread[first,5,main]:2
Thread[second,5,main]:1
Thread[first,5,main]:3
Thread[first,5,main]:4
Thread[second,5,main]:2
Thread[second,5,main]:3
Thread[second,5,main]:4
主线程与子线程:
class OneThread implements Runnable{
@Override
public void run() {
for(int i = 0;i < 5;i++)
System.out.println(Thread.currentThread() + ":" + i);
}
}
public class TestMoreThread {
public static void main(String[] args) {
OneThread oneThread = new OneThread();
Thread first = new Thread(oneThread,"first");
Thread second = new Thread(oneThread,"second");
first.start();
second.start();
System.out.println("主线程结束");
}
}
输出:
主线程结束
Thread[first,5,main]:0
Thread[second,5,main]:0
Thread[second,5,main]:1
Thread[first,5,main]:1
Thread[second,5,main]:2
Thread[first,5,main]:2
Thread[second,5,main]:3
Thread[first,5,main]:3
Thread[second,5,main]:4
Thread[first,5,main]:4
期望的输出是子线程输出完毕之后输出主线程结束,上述输出与期望结果不符,这是因为当主线程执行到输出语句时子线程没有结束,
要想得到期望的结果,有下面两种方式:
- 使用sleep()
public class TestMoreThread {
public static void main(String[] args) {
OneThread oneThread = new OneThread();
Thread first = new Thread(oneThread,"first");
Thread second = new Thread(oneThread,"second");
first.start();
second.start();
try {
Thread.sleep(1);//毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束");
}
}
使用sleep使主线程睡眠,子线程在1毫秒内执行完成,之后执行主线程,输出
不过用这种方式的话,如果子线程无法在sleep时间内执行完成,主线程的输出会穿插在子线程的输出中
想要使主线程必在子线程执行完后执行可以使用join(),让子线程先执行
public class TestMoreThread {
public static void main(String[] args) {
OneThread oneThread = new OneThread();
Thread first = new Thread(oneThread,"first");
Thread second = new Thread(oneThread,"second");
first.start();
second.start();
try {
first.join();
second.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主线程结束");
}
}
输出:
Thread[first,5,main]:0
Thread[second,5,main]:0
Thread[first,5,main]:1
Thread[first,5,main]:2
Thread[second,5,main]:1
Thread[first,5,main]:3
Thread[second,5,main]:2
Thread[first,5,main]:4
Thread[second,5,main]:3
Thread[second,5,main]:4
主线程结束
线程的优先级
- 理论上,优先级高的线程比优先级低的线程获得更多的CPU时间
- 实际上,线程获得的CPU时间由包括优先级在内的多个因素决定
- 理论上,等优先级的线程有同等的权力使用CPU
线程优先级从1——10
/**
* 线程可以获得的最低优先级
*/
public final static int MIN_PRIORITY = 1;
/**
* 线程的默认优先级
*/
public final static int NORM_PRIORITY = 5;
/**
* 线程可以获得的最高优先级
*/
public final static int MAX_PRIORITY = 10;
设置线程优先级:
//设置优先级
first.setPriority(10);//1 - 10
//获得优先级
first.getPriority();
Q.E.D.