**进程:**每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。(进程是资源分配的最小单位)
**线程:**同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
**线程和进程一样分为五个阶段:**创建、就绪、运行、阻塞、终止
**Java线程有六个状态:**NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞)、TIMED_WAITING(指定时间等待)、TERMINATED(终止)
Java线程是不区分 Ready(就绪)和 Running(运行)的,它们都是 Runnable 状态。
多进程是指操作系统能同时运行多个任务(程序),同一程序中有多个顺序流在执行。
在java中要想实现多线程,有两种手段,一种是继承Thread类,另外一种是实现Runable接口。(其实准确来讲,应该有三种,还有一种是实现Callable接口,并与Future、线程池结合使用)
public class MyThread extends Thread {
/**
* run 方法就是线性要执行的任务方法
*/
@Override
public void run() {
// 这个的代码,就是一条新的执行路径
// 这个执行路径的触发方式,不是调用 run 方法,而是通过 thread 对象的 start() 来启动任务
for (int i = 0; i < 10; i++) {
System.out.println("分支任务执行"+i);
}
}
}
public class Test {
/**
* 多线程技术
*/
public static void main(String[] args) {
MyThread m = new MyThread();
m.start();
for (int i = 0; i < 10; i++) {
System.out.println("主任务执行"+i);
}
}
}
运行结果每次都会不一样,这是两个线程相互抢占,使用抢占式分配的结果,故后续相同功能的代码运行结果省略:
主任务执行0
主任务执行1
分支任务执行0
主任务执行2
分支任务执行1
主任务执行3
分支任务执行2
分支任务执行3
主任务执行4
主任务执行5
主任务执行6
分支任务执行4
主任务执行7
分支任务执行5
主任务执行8
分支任务执行6
主任务执行9
分支任务执行7
分支任务执行8
分支任务执行9
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("分支任务执行"+i);
}
}
}.start();
for (int i = 0; i < 10; i++) {
System.out.println("主任务执行"+i);
}
}
public class MyRunnable implements Runnable {
@Override
public void run() {
// 线程的任务
for (int i = 0; i < 10; i++) {
System.out.println("分支任务执行"+i);
}
}
}
public class Test {
/**
* 多线程技术
*/
public static void main(String[] args) {
// 实现 Runnable
// 1. 创建一个任务对象
MyRunnable r = new MyRunnable();
// 2. 创建一个线程,并为其分配一个任务
Thread t = new Thread(r);
// 3. 执行这个线程
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("主任务执行"+i);
}
}
}
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("分支任务执行"+i);
}
}
});
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("主任务执行"+i);
}
}
注:括号代表重写的方法,方法名可省略,括号内部可传参数类型,大括号中是重写的方法内容,大括号外可传参数的值
public static void main(String[] args) {
Thread t = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("分支任务执行"+i);
}
});
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("主任务执行"+i);
}
}
另外:实现 Runnable 与继承 Thread 相比有如下优势
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
new Thread(new MainRunnable(),"分支任务").start();
}
static class MainRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
运行结果如下,若不传进程名称只传目标类,则会生成默认名称:Thread-0,后续创建的进程名称依次加一: Thread-1、Thread-2……
main
分支任务
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
System.out.println(i);
Thread.sleep(1000);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 1. e.printStackTrace();
// 2. System.out.println("发现了中断标记");
// 3.
System.out.println("发现了中断标记,令进程死亡");
return;
}
}
});
t.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
Thread.sleep(1000);
}
t.interrupt();
}