一、概述
1、什么是进程?
进程是指一个内存中运行的应用程序,每一个进程都有一个独立的内存空间。
2、什么是线程?
线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程,线程属于某个进程,线程没有自己的虚拟地址空间,与进程内的其它线程一起共享分配给该进程的所有资源。
对Java程序来说,当Dos命令窗口中输入:java HelloWorld 回车之后,会先启动JVM,而JVM就是一个进程。JVM再启动一个主线程main方法,同时再启动一个垃圾回收线程负责看护,回收垃圾。最起码,现在的Java程序中至少有两个线程并发:一个是垃圾回收线程,一个是执行main方法的主线程。
线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
3、线程和进程是什么关系?
进程可以看作是现实生活中的公司,线程可以看作是公司当中的某个员工。
注意:进程A和进程B的内存独立不共享。线程A和线程B之间,堆内存和方法区之间内存共享;但是栈内存独立,一个线程一个栈。
4、简单说下多线程并发
假设启动10个线程,会有10个栈空间,每个栈和每个栈之间互不干扰,各自执行各自的,这就是多线程并发。
例子:火车站可以看作是一个进程。火车站中的每一个售票窗口可以看作是一个线程。我在窗口1购票,你在窗口2购票,你不需要等我,我也不需要等你,所有多线程并发可以提高效率。
Java中之所以有多线程机制,目的就是为了提高程序的处理效率。
5、一个线程包含以下内容:
- 一个指向当前被执行指令的指令指针;
- 一个栈;
- 一个寄存器值的集合,定义了一部分描述正在执行线程的处理器状态的值;
- 一个私有的数据区。
6、关于线程的生命周期
- 新建状态
- 就绪状态
- 运行状态
- 阻塞状态
- 死亡状态
二、线程的创建
1、编写一个类,继承java.lang.Thread,重写run方法
public class ThreadTest01 {
public static void main(String[] args) {
//这里是main方法,这里的代码属于主线程,在主栈中运行。
//新建一个分支线程对象。
MyThread myThread = new MyThread();
//启动多线程
//start()方法的作用是:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成后,瞬间就结束了。
//这段代码的任务只是为了开启一个新的栈空间,只要新的栈空间开辟出来了,start()方法就结束了。线程就启动成功了。
//启动成功的线程会自动调用run方法,并且run方法在分支栈的栈底部(压栈)。
//run方法在分支栈的栈底部,main方法在主栈的栈底部。run和main是平级的。
myThread.start();
//这里的代码还是在主线程中。
for(int i = 0; i < 100; i++){
System.out.println("主线程--->" + i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
//编写程序,这段程序运行在分支线程中(分支栈)。
for(int i = 0; i < 100; i++){
System.out.println("分支线程--->" + i);
}
}
}
2、编写一个类,实现java.lang.Runnable接口
public class ThreadTest02 {
public static void main(String[] args) {
//创建一个可运行的对象
MyRunnable r = new MyRunnable();
//将可运行的对象封装成一个线程对象
Thread t = new Thread(r);
//Thread t = new Thread(new MyRunnable()); 合并代码
//启动线程
t.start();
for(int i = 0; i < 100; i++){
System.out.println("主线程--->" + i);
}
}
}
//这并不是一个线程类,是一个可运行的类。它还不是一个线程。
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 0; i < 100; i++){
System.out.println("分支线程--->" + i);
}
}
}
2.1、使用匿名内部类编写
public class ThreadTest03 {
public static void main(String[] args) {
//采用匿名内部类编写
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i < 100; i++){
System.out.println("分支线程--->" + i);
}
}
});
//启动线程
t.start();
for(int i = 0; i < 100; i++){
System.out.println("主线程--->" + i);
}
}
}
3、使用Callable接口创建线程
/*
线程执行的第三种方式:
实现Callable接口
这种方式的优点:可以获取到线程的执行结果
这种方式的缺点:效率较低,在获取t线程执行结果的时候,当前线程受阻塞,效率较低。
*/