1.进程与线程
- 进程是正在运行着的程序,是资源分配的最小单位。
- 一个进程中可以有多个线程,多个线程共享同一份系统资源,线程是操作系统调度运行的基本单位。
2.进程与线程的区别
- 进程包含线程
- (内存空间和文件描述表)进程有自己独立的内存空间和文件描述表;同一个进程中的多个线程之间之间共享同一份地址空间和文件描述表;
- (操作系统基本单位)进程是操作系统资源分配的基本单位;线程是操作系统调度运行的基本单位;
- (独立性)进程之间具有独立性,一个进程挂了,不会影响到其他的进程;但是同一个进程里的多个线程之间,一个线程挂了,可能会把整个进程带走,影响到其他线程。
3.线程与主线程
以一个java程序为例,main方法里边的程序为主线程,在main方法中启动的为线程,线程的执行代码在run()方法中实现,线程启动后自动调用run()方法,run()可以理解为线程的入口
4.线程的创建
public class MyThread1 extends Thread{
public void run(){
System.out.println("线程"+this.getName()+"正在运行");
}
}
public class Main {
public static void main(String[] args){
Thread t1 = new MyThread1();
Thread t2 = new MyThread1();
Thread t3 = new MyThread1();
//线程1启动
t1.start();
//线程2启动
t2.start();
//线程3启动
t3.start();
System.out.println("主线程正在运行");
}
}
主线程和线程之间的执行顺序是不确定的,由操作系统调度决定
可能的输出顺序
-
可能输出:
Copy Code Main thread is running. Thread is running: Thread-0 Thread is running: Thread-1 Thread is running: Thread-2 -
也可能输出:
Copy Code Thread is running: Thread-1 Thread is running: Thread-0 Main thread is running. Thread is running: Thread-2
下面的代码执行过程可以更直观的看到线程和主线程在交替运行
//一个线程实例只能被启动一次,但可以创建多个线程
class MyThread extends Thread {
public void run() {
while (true) {
System.out.println("tttt");
}
}
}
public class Main {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
while (true) {
System.out.println("mmmm");
}
}
}
5.线程创建出现的问题
一个线程实例只能被启动该一次,
public class Main {
public static void main(String[] args) {
Thread t1 = new MyThread1();
Thread t2 = new MyThread1();
Thread t3 = new MyThread1();
int i = 7; //i 是共享资源
while (i != 0) {//多次启动报错
//线程1启动
t1.start();
//线程2启动
t2.start();
//线程3启动
t3.start();
System.out.println("主线程正在运行");
i--;
}
}
}
6.线程创建的方式
(1)继承Thread类,重写run()方法
public class MyThread1 extends Thread{
public void run(){
System.out.println("线程"+this.getName()+"正在运行");
}
}
public class Main {
public static void main(String[] args){
Thread t1 = new MyThread1();
Thread t2 = new MyThread1();
Thread t3 = new MyThread1();
//线程1启动
t1.start();
//线程2启动
t2.start();
//线程3启动
t3.start();
System.out.println("主线程正在运行");
}
}
(2)实现Runnable接口重写run()
class MyThread implements Runnable {
public void run() {
while (true) {
System.out.println("tttt");
}
}
}
public class Main {
public static void main(String[] args) {
Thread t = new Thread(new MyThread());//初始化 Thread类,将MyThread类创建的线程信息提供给Thread类的实例,使得t可以调用MyThread()的信息,不能直接用new MyThread(),因为不是子父类关系
t.start();
while (true) {
System.out.println("mmmm");
}
}
}
为什么使用 Runnable 而不是直接继承 Thread
虽然你也可以直接继承 Thread 类,但实现 Runnable 接口有以下优点:
- 更好的灵活性:Java 是单继承的,因此如果你选择继承
Thread,就不能再继承其他类。实现Runnable接口允许你同时继承其他类。 - 更易于共享资源:多个线程可以共享同一个
Runnable实例,而每个Thread实例都是独立的。这样更方便在线程之间共享数据和状态。
(3)继承Thread类,重写run,使用匿名类
public class Main {
public static void main(String args[]){
Thread t= new Thread(){
public void run(){
while(true){
System.out.println("lll");
}
}
};
t.start();
while(true) {
System.out.println("zzz");
}
}
}
(4)实现Runnable接口,重写run,使用匿名类
public class Main {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println("tttt");
}
}
});
t.start();
while (true) {
System.out.println("mmmm");
}
}
}
(5)使用lambda表达式
public class ThreadDemo5 {
public static void main(String[] args) {
Thread t = new Thread(() -> { //和Runnable匿名内部类写法差不多
while (true) {
System.out.println("ttt");
}
});
t.start();
while(true) {
System.out.println("mmm");
}
}
}