线程的基本概念

进程与线程

  • 进程
    进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。
    在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。
  • 线程
    线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的方法区资源,但每个线程有自己的程序计数器虚拟机栈本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。

并发与并行

  • 并发: 同一时间段,多个任务都在执行 (单位时间内不一定同时执行);
  • 并行: 单位时间内,多个任务同时执行。

线程的创建方式

方法一:继承Thread类,作为线程对象存在(继承Thread对象)

public class Test extends Thread {
    @Override
    public void run() {
       while (!interrupted()){
           System.out.println(Thread.currentThread().getName()+"执行了线程");
       }
    }
    public static void main(String[] args) {
        Test t=new Test();
        Test t1=new Test();
        t.start();
        t1.start();
        //中断第一个线程
        t.interrupt();
        }
}

方法二:实现runnable接口

public class Test implements Runnable {
    @Override
    public void run() {

        System.out.println(Thread.currentThread().getName() + "执行了线程");
    }
    public static void main(String[] args) {
        Thread t = new Thread(new Test());
        t.start();
    }
}
//使用匿名内部类方式 lambda和匿名内部来类似
public static void main(String[] args) {
        new Thread(() -> System.out.println("执行了线程")).start();
    }   

方法三:创建带返回值的线程

public class CreatThreadDemo4 implements Callable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CreatThreadDemo4 demo4 = new CreatThreadDemo4();

        FutureTask<Integer> task = new FutureTask<Integer>(demo4); //FutureTask最终实现的是runnable接口

        Thread thread = new Thread(task);

        thread.start();

        System.out.println("我可以在这里做点别的业务逻辑...因为FutureTask是提前完成任务");
        //拿出线程执行的返回值
        Integer result = task.get();
        System.out.println("线程中运算的结果为:"+result);
    }

    //重写Callable接口的call方法
    @Override
    public Object call() throws Exception {
        int result = 1;
        System.out.println("业务逻辑计算中...");
        Thread.sleep(3000);
        return result;
    }
}

线程的状态

<img src="./线程学习/1.png" alt="在这里插入图片描述" style="zoom:50%;" /

  1. 新建(New): 创建后尚未启动。

  2. 就绪(Runnable): 线程准备运行,不一定立马就能开始执行。

  3. **运行中(Running):**进程正在执行线程的代码。

  4. 阻塞(Blocking): 等待获取一个排它锁,如果其线程释放了锁就会结束此状态。

  5. 无限期等待(Waiting): 等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。

    进入方法退出方法
    没有设置 Timeout 参数的 Object.wait() 方法Object.notify() / Object.notifyAll()
    没有设置 Timeout 参数的 Thread.join() 方法被调用的线程执行完毕
    LockSupport.park() 方法-
  6. 限期等待(Timed Waiting): 无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。

    进入方法退出方法
    Thread.sleep() 方法时间结束
    设置了 Timeout 参数的 Object.wait() 方法时间结束 / Object.notify() / Object.notifyAll()
    设置了 Timeout 参数的 Thread.join() 方法时间结束 / 被调用的线程执行完毕
    LockSupport.parkNanos() 方法-
    LockSupport.parkUntil() 方法-
  7. 死亡(Dead): 线程完成了执行。

多线程的一些常用方法

  • start(): 启动线程
  • currentThread() : 获取当前线程对象
  • getPriority(): 获取当前线程的优先级
  • setPriority(int newPriority) : 设置当前线程的优先级(1-10,1代表最低优先级,10代表最高优先级)
  • isAlive() :判断线程是否处于活动状态 (线程调用start后,即处于活动状态)
  • sleep(long millis) :线程对象调用sleep(time)方法后,当前线程会等待指定的时间(time),并让出cpu执行权,但是它的监控状态依然当前对象的保持者(不会释放对象锁,休眠的线程会进入阻塞中泰中),当指定的时间到了又会自动恢复运行状态。
  • yield() :放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片(不会释放锁)
  • interrupt() :调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞、限期等待或者无限期等待状态,那么就会抛出 InterruptedException,从而提前结束该线程。但是不能中断 I/O 阻塞和 synchronized 锁阻塞。
  • interrupted :如果一个线程的 run() 方法执行一个无限循环,并且没有执行 sleep() 等会抛出 InterruptedException 的操作,那么调用线程的 interrupt() 方法就无法使线程提前结束。调用 interrupt() 方法会设置线程的中断标记,此时调用 interrupted() 方法会返回 true。因此可以在循环体中使用 interrupted() 方法来判断线程是否处于中断状态,从而提前结束线程。
  • isInterrupted :判断当前线程对象的状态是否为中断状态,不会重置当前线程的中断状态
  • isDaemon( ) :判断是否为守护线程
  • setDaemon(boolean on) :设置为守护线程,守护线程是程序运行时在后台提供服务的线程,不属于程序中不可或缺的部分。当所有非守护线程结束时,程序也就终止,同时会杀死所有守护线程。main() 属于非守护线程。
  • join() :在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。并且join()方法是会释放锁的,因为底层使用 wait() 方法来实现的。{% post_link 并发编程/多线程/join的理解 join的理解%}
  • wait() 使当前线程阻塞,直到调用notify(),则被唤醒。,wait(long timeOut)使当前线程阻塞,直到调用notify()或时长超过timeOut,则被唤醒。且wait是Object的方法,会释放锁
  • notify() / notifyAll():唤醒单个线程/唤醒所有线程
    wait()和notify()、notifyAll()方法的调用都必须在synchronized修饰的方法或者代码块中调用,使用过程中必须获得对象锁,否则会抛出java.lang.IllegalMonitorStateException的异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值