一个进程可以包含多个线程,但至少要有一个线程。

多进程模式:每个进程只有一个线程

多线程模式:一个进程有多个线程

优缺点:

  • 进程比线程开销大、通信慢
  • 多进程比多线程稳定性高

一个java程序就是一个JVM进程,JVM进程用一个主线程来执行<font style="background-color:rgb(248, 249, 250);">main()</font>方法,在<font style="background-color:rgb(248, 249, 250);">main()</font>方法内部又可以启动多个线程。多线程需要同步读取共享数据。

方法一:从<font style="background-color:rgb(248, 249, 250);">Thread</font>派生一个子类,并覆写<font style="background-color:rgb(248, 249, 250);">run()</font>方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.example;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.LinkedList;
import java.util.List;

public class Main {
public static void main(String[] args) throws IOException {
Thread t1 = new Thread();
t1.start();
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Hello World");
}
}

方法二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.example;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.LinkedList;
import java.util.List;

public class Main {
public static void main(String[] args) throws IOException {
Thread t1 = new Thread(new MyRunnable());
ti.start();
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Hello World");
}
}

方法三:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.example;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.LinkedList;
import java.util.List;

public class Main {
public static void main(String[] args) throws IOException {
Thread t1 = new Thread(()->{
System.out.println("hello world");
});
t1.start();
}
}

执行顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package org.example;
import java.io.*;
import java.nio.file.*;


public class Main {
public static void main(String[] args) throws IOException {
System.out.println("main run...");
Thread t1 = new Thread(){
public void run(){
System.out.println("thread run...");
System.out.println("thread end...");
}
};
t1.start();
System.out.println("main end...");
}
}

main线程执行的代码有4行,首先会打印<font style="background-color:rgb(248, 249, 250);">main run...</font>,然后创建Thread对象,接着调用<font style="background-color:rgb(248, 249, 250);">start()</font>启动新线程。所以<font style="background-color:rgb(248, 249, 250);">mian end...</font>与新线程是同时执行的,程序本身无法确定线程的调度顺序。

可以使用<font style="background-color:rgb(248, 249, 250);">Thread.sleep()</font>强制当前线程暂停来控制哪个线程线执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.example;
import java.io.*;
import java.nio.file.*;


public class Main {
public static void main(String[] args) throws IOException {
System.out.println("main run...");
Thread t1 = new Thread(){
public void run(){
System.out.println("thread run...");
try{Thread.sleep(10);}catch(Exception e){}
System.out.println("thread end...");
}
};
t1.start();
try{Thread.sleep(20);}catch(Exception e){}
System.out.println("main end...");
}
}

注意:

  • 在mian线程内直接调用<font style="background-color:rgb(248, 249, 250);">run()</font>方法不会新启动线程,必须调用<font style="background-color:rgb(248, 249, 250);">Thread</font>实例的<font style="background-color:rgb(248, 249, 250);">start()</font>方法才能启动新线程。
  • 一个线程对象只能调用一次<font style="background-color:rgb(248, 249, 250);">start()</font>方法。

也可以通过<font style="background-color:rgb(248, 249, 250);">Thread.setPriority(int n)</font>来设置线程的优先级(1~10,默认值是5),操作系统对高优先级线程可能调度更频繁,但不能保证一定会先执行。

线程状态

  • <font style="background-color:rgb(248, 249, 250);">New</font>:新创建的线程,尚未执行;
  • <font style="background-color:rgb(248, 249, 250);">Runnable</font>:运行中的线程,正在执行<font style="background-color:rgb(248, 249, 250);">run()</font>方法的Java代码;
  • <font style="background-color:rgb(248, 249, 250);">Blocked</font>:运行中的线程,因为某些操作被阻塞而挂起;
  • <font style="background-color:rgb(248, 249, 250);">Waiting</font>:运行中的线程,因为某些操作在等待中;
  • <font style="background-color:rgb(248, 249, 250);">Timed Waiting</font>:运行中的线程,因为执行<font style="background-color:rgb(248, 249, 250);">sleep()</font>方法正在计时等待;
  • <font style="background-color:rgb(248, 249, 250);">Terminated</font>:线程已终止,因为<font style="background-color:rgb(248, 249, 250);">run()</font>方法执行完毕。

线程终止的原因:

  • 线程正常终止:<font style="background-color:rgb(248, 249, 250);">run()</font>方法执行到语句返回;
  • 线程意外终止:<font style="background-color:rgb(248, 249, 250);">run()</font>因为未捕获的异常导致线程终止;
  • 对某个线程的<font style="background-color:rgb(248, 249, 250);">Thread</font>实例调用<font style="background-color:rgb(248, 249, 250);">stop()</font>方法强制终止。

使用<font style="background-color:rgb(248, 249, 250);">join()</font><font style="background-color:rgb(248, 249, 250);">join(long)</font>可以让主线程等待子线程结束后再运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.example;
import java.io.*;
import java.nio.file.*;


public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
Thread t=new Thread(()->{
System.out.println("hello");
});
System.out.println("start");
t.start();
t.join();
System.out.println("end");
}
}

中断线程

<font style="background-color:rgb(248, 249, 250);">Thread.interrupt()</font>:中断线程

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
package org.example;
import java.io.*;
import java.nio.file.*;


public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
Thread t=new MyThread();
t.start();
t.sleep(10);
t.interrupt();
t.join();
System.out.println("end");
}
}
class MyThread extends Thread {
@Override
public void run() {
int i=0;
while(!isInterrupted()) {
i++;
System.out.println(i+"hello~");
}
}
}