<JavaEE><多线程>线程Thread类,创建线程及各种线程操作

目录

一、线程、进程

什么是进程?

什么是线程?

线程和进程的区别

二、创建线程类

方法1 继承Thread类

方法2 实现Runnable接口

方法3 匿名内部类方式

方法4 Lambda表达式方式(常用)

三、调用线程:Thread类的方法

构造方法

 启动线程

中断线程

等待线程

休眠线程

获取当前线程对象的引用

获取线程相关属性方法


一、线程、进程

什么是进程?

进程是操作系统对正在运行程序的一种抽象,是操作系统进行资源分配的基本单位,我们可以认为每个运行于操作系统上的应用程序都是一个进程。

什么是线程?

线程是一个“执行流”,每个线程都可以按照循序执行自己的代码,而在一个进程中可以有多个线程,也就是说可以支持同时执行多份代码。

多线程的API是由操作系统提供,Java来进行抽象和封装后再由程序员来使用的,具体为Java标准库中的Thread类(在Java默认引用的java.lang包中)。

线程和进程的区别

  • 进程与线程是包含与被包含的关系,每个进程至少有一个线程存在,即主线程
  • 进程和进程之间相互独立,不共享内存空间,同一个进程的线程之间共享一份内存空间,形象来说就是对于一个建筑工程,每个人负责不同的项目,但都是在操作同一份空间。
  • 进程是系统分配资源的最小单位,线程是系统图调度的最小单位
  • 一个进程挂了一般不会影响其他进程(相互独立),但是一个线程挂了,就可能把进程内的其他线程都一波带走

二、创建线程类

继承Thread类可以创建一个线程类,我们可以通过在主线程中实例化它,随后创建一个不同于主线程的另一个线程来同时执行多份代码,两份代码同时执行,每条代码执行的先后循序取决于系统调度器。

线程执行的代码通过重写run()方法来实现,具体创建方法如下:

方法1 继承Thread类

class MyTread extends Thread {
    @Override //重写run方法
    public void run() {
        //以下为线程执行的具体代码
        while(true) {
            System.out.println("hello thread");
            try {
                //线程休眠
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class ThreadDemo1 {

    public static void main(String[] args) {
        //实列化线程类
        Thread t = new MyThread();
        //启动线程
        t.start();
    }
}

方法2 实现Runnable接口

Thread的构造方法除了Thread( ),还有Thread(Runnable target)

我们可以在实现了Runnable接口的类中实现run方法,将该类的实列作为参数,同样能达到创建线程的目的。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        while(true) {
            System.out.println("hello runnable");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

public class ThreadDemo1 {

    public static void main(String[] args) {
        //实列化线程类
        Thread t = new Thread(new MyRunnable());
        //启动线程
        t.start();
    }
}

方法3 匿名内部类方式

    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("重写run方法");
            }
        };

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("重写run方法");
            }
        });
        //启动线程
        t.start();
    }

方法4 Lambda表达式方式(常用)

public class ThreadDemo1 {

    public static void main(String[] args) {
        Thread t = new Thread(() -> System.out.println("重写Runnable中的run方法"));
        //启动线程
        t.start();
    }
}

三、调用线程:Thread类的方法

构造方法

  • Thread( )                            创建线程对象
  • Thread(Runnable target ) 使用Runnable对象创建线程对象
  • Thread(String name)         创建线程对象,并对线程进行命名
  • Thread(Runnable target, String name) 使用Runnable对象创建线程对象,并命名
  • Thread(ThreadGroup group, Runnable target) 线程可以被用来进行分组管理

未对线程进行命名时,线程默认的命名格式为“Thread-数字”(使用Java自带的jconsole进行观察)

 启动线程

使用构造方法创建出线程类并实列化,并不是真的创建出了一个线程,只有在调用了start()方法后才会真正在操作系统底层创建出一个线程出来,

Thread.start( );

使用线程实例调用start方法,创建相应的线程,并执行run中的代码

中断线程

调用start方法后,线程不将代码执行完毕是不会结束的,如果想要将线程中断,那么就需要调用interrupt()方法对线程进行通知,告诉它你想要结束线程,至于线程是否结束,该怎样结束还要依据具体代码来分情况讨论。

  • public void interrupt(  );
  • Thread内部包含了⼀个boolean类型的变量作为线程是否被中断的标记,调用interrupt中断线程
  • public static boolean interrupted( )
  • 判断当前线程标志位是否被设置,被设置(调用了interrupt方法)则返回true,未设置则返回false
  • public boolean isInterrupted(  )
  • 在使用Runnable接口实现线程类时,通过 " Thread.currentThread( ).isInterrupted( ) "达到interrupted方法的效果,Thread.currentThread( )方法可以获取当前线程的引用

调用interrupt可能出现以下两种情况:

情况1:线程因为调用sleep/wait/join等方法而阻塞挂起时调用

该情况下将抛出interruptedException异常,并清除标志位(不直接结束),是否继续执行取决于catch中代码的写法

    public static void main(String[] args) {
        //实列化线程对象,lambda方式
        Thread t1 = new Thread(() -> {
            //每秒输出
            while(true) {
                System.out.println("t1 dashb");
                try {
                    //线程休眠
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //可以break退出该循环,跳出本次循环
                    //也可以不进行处理,继续执行
                }
            }
        });
        //启动线程
        t1.start();
        //两秒后中断线程
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //中断线程
        t1.interrupt();
        System.out.println("中断线程");
        while(true) {
            System.out.println("main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

当不在cath中对异常进行任何处理,可以观察到线程仍旧在执行代码,表明标志位被清除。

当然,我们也可以break直接退出本次循环,之后可以顺利结束线程,又或者执行一些别的代码都可以

这种异常通知的方式,给予了我们程序员更大的操作空间。

情况2:正常情况调用

调用interrupt方法后标志位由false被设置为true,该boolean类型值可通过isInterrupted或interrupted获取,可通过该方法的返回值判断是否要中断线程

    public static void main(String[] args) {
        //实列化线程对象,lambda方式
        Thread t1 = new Thread(() -> {
            //每秒输出
            while(!Thread.currentThread().isInterrupted()) {
                System.out.println("t1 dashb");
            }
        });
        //启动线程
        t1.start();
        //1毫秒后中断线程
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //中断线程
        t1.interrupt();
        System.out.println("中断线程");
        while(true) {
            System.out.println("main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

等待线程

有些时候我们需要让某个线程完成其工作后才能继续向下工作,例如当过年吃年夜饭时,只有当所有亲人都到位了才能开饭,在所有人到齐之前,开饭操作只能等待人齐操作完成后才能执行。

  • public void join(  )                                 
  • 等待调用线程结束
  • public void join(long millis)                   
  • 等待调用线程结束,最多等待millis秒
  • public void join(long millis, int nanos)   
  • 更高精度等待
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            int s = 0;
           for(int i = 0; i < 3; i++) {
               System.out.println("t1执行中");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
        });
        t1.start();
        System.out.println("t1线程启动");
        //调用join方法
        t1.join();
        System.out.println("t1线程结束");
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            int s = 0;
           for(int i = 0; i < 3; i++) {
               System.out.println("t1执行中");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
        });
        t1.start();
        System.out.println("t1线程启动");
        //调用join方法
        t1.join(2);
        System.out.println("等待结束");
    }

休眠线程

Thread类中的方法。因为线程的调度是不可控的,所以,这个⽅法只能保证实际休眠时间是⼤于等于参数设置的休眠时间的

  • public static void sleep(long millis)
  • 休眠指定毫秒
  • public static void sleep(long millis, int nanos)
  • 更高精度

获取当前线程对象的引用

当使用Runnable接口实现线程类时,一些Thread类的方法无法直接调用,这时候就可以通过Thread类的currentThread()方法来获取当前线程对象的引用,从而可以调用Thread类中的方法。

  • public static Thread currentThread(  )
  • 获取当前线程的引用

在中断线程部分我们用它来获取了当前线程对象,并通过返回的引用调用了isInterrupted方法

在需要大量该操作时也可以这样:

Thread thread = Thread.currentThread();

获取线程相关属性方法

  • ID                          getId()
  • ID是线程的唯⼀标识,不同线程不会重复
  • 名称                       getName( )
  • 名称是各种调试⼯具⽤到
  • 状态                       getState( )
  • 状态表⽰线程当前所处的⼀个情况
  • 优先级                    getPriority( )
  • 优先级⾼的线程理论上来说更容易被调度到
  • 是否是后台线程      isDaemon( )
  • 关于后台线程,需要记住⼀点:JVM会在⼀个进程的所有⾮后台线程结束后,才会结束运⾏。
  • 是否存活                 getAlive( )
  • 是否存活,即简单的理解,为run⽅法是否运⾏结束了
  • 是否被中断             isInterrupted( )
  • 判断线程是否被中断

博主是Java新人,每位同志的支持都会给博主莫大的动力,如果有任何疑问,或者发现了任何错误,都欢迎大家在评论区交流“ψ(`∇´)ψ

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值