多线程(java)

目录

一 认识线程

概念

为什么要有线程

二 Java创建线程

1.继承Thread重写run;

2.实现Runnable,重写run

3.继承Thread,匿名内部类

4.实现Runnable,匿名内部类

5.lambda表达式

6.Callable

三 Thread

方法

常见构造方法

常用属性

中断线程(isInterrupted)

等待一个线程(join)

线程的状态


一 认识线程

概念

一个线程就是一个"执行流",每个线程之间都可以按照顺序执行自己的代码.多个线程之间"同时"执行着多

为什么要有线程

这里我们需要先需要了解进程

我们的操作系统对下要管理好各种硬件设备,对上要给软件提供稳定的运行环境;

而我们在运行一个软件的时候,就需要进行资源分配,而进程是操作系统进行资源分配的基本单位,此处涉及到的资源包括但不限于:内存,硬盘,CPU等

当进程多了我们就需要进行进程管理

所谓管理,就是分两步

1.描述一个进程:使用结构体/类,把一个进程有哪些信息,表示出来

2.组织这些进程:使用一定的数据结构,把这些结构体/对象,放到一起

一个进程的结构体(PCB)有哪些属性?

这里只挑几个核心的

1.pid:每个进程的唯一身份标识

2.内存指针:当前这个进程使用的那块内存

3.文件描述符表:

硬盘上存储的数据,就是以文件为单位进行整理;

进程每打开一个文件,就会产生一个"文件描述符"来标识这个被打开的文件;

但一个进程可能会打开很多文件,这样就会产生一组文件描述符,把这些文件描述符放到一个顺序表这样的结构里,就构成了文件描述符表

而每当我们创造一个进程的时候,就会消耗相对较多的资源,但我们可能会不能完全利用起来;

而且每次使用一个进程时,就得进行创建,不使用的时候就得进行销毁,这样是非常耗费时间的;

这个时候,我们就发明了线程,线程是一小块一小块的存在于进程里的;

当我们创建第一个线程的时候,操作系统就会申请系统资源去建立一个进程,当后续在创建线程,就不必再申请资源了,创建和销毁的效率就提高了不少

所以线程是操作系统调度运行的基本单位

面试题:进程和线程的区别

1.进程包含线程

2.进程具有自己独立的内存空间和文件描述符表.同一个进程中的多个线程之间,共享同一份地址空间和文件描述符表

3.进程是操作系统资源分配的基本单位,线程是操作系统调度执行的基本单位

4.进程之间具有独立性,一个进程挂了,不会影响到别的进程;同一个进程里的多个线程之间,一个线程挂了,可能会把整个进程带走,影响到其他线程

二 Java创建线程

1.继承Thread重写run;

class MyThread1 extends Thread{
    @Override
    public void run() {
        while(true){
            System.out.println("main");
        }
    }
}

public class ThreadDemo1 {

    public static void main(String[] args) {
        MyThread1 thread = new MyThread1();
        thread.start();
        while(true){
            System.out.println("main");
        }
    }
}

2.实现Runnable,重写run

class MyThread implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class ThreadDemo1{
    public static void main(String[] args) throws InterruptedException {
        //实现Runnable的实例
        MyThread2 myThread = new MyThread2();
        //将Runnable的实例作为参数
        Thread thread = new Thread(myThread2);
        thread.start();
        while(true){
            System.out.println("main");
            Thread.sleep(1000);
        }
    }
}

3.继承Thread,匿名内部类

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run() {
                while(true){
                    System.out.println("thread");
                }
            }
        };
        thread.start();
        
        while(true){
            System.out.println("main");
        }
    }

}

4.实现Runnable,匿名内部类

public class ThreadDemo4 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    System.out.println("thread");
                }
            }
        });
        thread.start();
        
        while (true){
            System.out.println("main");
        }
    }
}

5.lambda表达式

也是最常用的一个

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(() ->{
            while(true){
                System.out.println("thread");
            }
        });
        thread.start();

        while(true){
            System.out.println("main");
        }
    }
}

6.Callable

Callable的用法非常类似于Runnable,描述一个线程要干啥

Runnable通过run方法描述,返回值为void,

Callable通过call方法描述,返回值为一个泛型;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//Callable
public class ThreadDemo6 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> callable = new Callable<Integer>() {
            int sum = 0;
            //计算1+2+3.......+1000
            @Override
            public Integer call() throws Exception {
                for(int i = 0; i <= 1000; i++){
                    sum += i;
                }
                return sum;
            }
        };
        //进行打包
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread thread = new Thread(futureTask);
        thread.start();
        //得到返回值
        System.out.println(futureTask.get());
    }
}

Thread不能直接传Callable,需要用FutureTask进行包装;

FutureTask的get方法在Thread的线程没有进行完时会进行阻塞等待

三 Thread

方法

 isDaemon():

true表示是后台线程 false表示是前台线程

前台线程会阻止java进程结束 必须得java进程中所有的前台线程都执行完java进程才能结束;

创建的线程默认是前台的;

可以通过setDaemon设置成后台

常见构造方法

常用属性

start方法: 真正从系统这里,创建一个线程,新的线程将会执行run方法.

run方法: 表示了线程的入口方法是啥(线程启动起来,要执行哪些逻辑)

中断线程(isInterrupted)

public class ThreadDemo7 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            //currentThread是获取当前线程实例
            //isInterrupted就是thread对象里自带的一个标志位
            while(!Thread.currentThread().isInterrupted()){
                System.out.println("thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        thread.interrupt();

    }
}

interrupt方法的作用:

1.设置标志位为true

2.如果该线程正在阻塞(比如执行sleep),此时就会把阻塞状态唤醒;通过抛出异常的方式让sleep立即结束

注意:当sleep被唤醒的时候,sleep会自动把isInterrupted标志位给清空(true -> false)

等待一个线程(join)

public class ThreadDemo8 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("thread");
        });
        thread.start();
        thread.join();

        System.out.println("main");
    }
}

main线程运行到join时会陷入阻塞,等待thread执行完

thread.join()会等到thread执行完

thread.join(time)在time内等待

线程的状态

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值