【JavaEE】Thread类的基本使用

1.线程创建

在Java中,由Thread类来描述线程,所以要创建线程就必须先得创建Thread对象。
主要用到Thread类中两个构造器:

Thread()

Thread(Runnable target)

方式1:继承Thread类,重写run方法。

MyThread类:

public class MyThread extends Thread{
    @Override
    public void run(){
        System.out.println("执行run方法");
    }
}

Test测试类:

public class Test {
    public static void main(String[] args) {
        //创建线程
        MyThread t = new MyThread();
        //调用start方法启动线程
        t.start();
    }
}

运行结果:

执行run方法

Plus:为什么要继承Thread类?并且重写run()方法
因为创建完的线程是从run()方法开始执行的。我们要往run()方法中写代码。
写完代码后,调用start()启动线程,然后线程执行run()方法里的代码。


方式2:实现Runnnable接口,重写run()方法
Thread类有一个有参构造方法,如下:

Thread(Runnable target)  

只需让一个类实现Runnable接口,然后将new对象,传给这个构造器即可。

MyThread2类:

public class MyThead2 implements Runnable{
    @Override
    public void run() {
        System.out.println("实现Runnable接口");
    }
}

Test测试类:

public class Test {
    public static void main(String[] args) {
    	//创建Thread对象
        Thread t = new Thread(new MyThead2());
        //开启线程
        t.start();
    }
}

运行结果:

实现Runnable接口

方式3:使用匿名内部类创建对象

Test测试类:

public class Test {
   public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("使用匿名内部类");
            }
        });
        t.start();
    }
}

运行结果:

使用匿名内部类

方式4:使用Lambda表达式
Runnable接口源码如下:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

因为这个接口是函数式接口,所以可用Lambda表达式。

Test测试类:

public class Test {
    public static void main(String[] args) {
        Runnable obj = ()->{
            System.out.println("使用lambda表达式");
        };
        Thread t = new Thread(obj);
        t.start();
    }
}

或者直接传参:

public class Test {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            System.out.println("使用lambda表达式");
        });
        t.start();
    }
}

运行结果:

使用lambda表达式

2.线程中断

如果我们想中断一个在运行的线程,就可用Thread.interrupted()来获取当前线程的中断状态,返回值为true或者false。默认为false,但我们可以通过Thread类里的对象方法interrupt()使返回值变为true
代码如下:

public class ThreadInterupted1 {
    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
            while (!Thread.interrupted()) {
                System.out.println("线程正在运行中...");
            }
            System.out.println("线程被中断!");
        });
        //创建线程
        t1.start();

        //主线程休眠一秒
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //中断线程
        t1.interrupt();
    }
}
线程正在运行中...
线程正在运行中...
线程正在运行中...
线程正在运行中...
线程正在运行中...
...
...
...
线程被中断!

中断线程的时候刚好线程在休眠(sleep)的情况:
在这里插入图片描述

  1. 执行interrupt()方法后,Thead.interrupted()的返回值变为true
  2. 此时,线程如果处于睡眠状态,会从睡眠状态变为可运行状态
    而且会把Thead.interrupted()的返回值改为又改为false
  3. 最后,sleep()方法会抛出异常。

下面是代码演示:

public class ThreadInterupted2 {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            while (!Thread.interrupted()) {
                System.out.println("线程运行中...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();

        //把主线程睡眠2秒
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //中断子线程
        thread.interrupt();
    }
}

创建完线程后,我让主线程先睡眠2秒,让子线程执行一段时间。
之后,中断子线程。此时,子线程大概率是处于睡眠状态的,所以会依照上面动画的情况执行。
结果如下:

线程运行中...
线程运行中...
线程运行中...
线程运行中...
java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at blog.ThreadInterupted2.lambda$main$0(ThreadInterupted2.java:14)
	at java.base/java.lang.Thread.run(Thread.java:833)
线程运行中...
线程运行中...
线程运行中...
线程运行中...
...
...

子线程抛出了异常,但是子线程代码还在运行。
如果要让线程抛出异常后结束运行,那就要在catch代码块中加break关键字。

代码如下:

try {
      Thread.sleep(1000);
  } catch (InterruptedException e) {
      e.printStackTrace();
      break;
  }

正常运行:

线程运行中...
线程运行中...
线程运行中...
java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at blog.ThreadInterupted2.lambda$main$0(ThreadInterupted2.java:14)
	at java.base/java.lang.Thread.run(Thread.java:833)

3.线程等待

由于多个线程之间执行顺序是随机的,无法确定线程的执行顺序。
但可以通过人工干预使得线程线程之间相对有序。
Thread类里有join()实例方法,通过调用这个方法,就可以使得线程进入等待状态。

public final void join() throws InterruptedException {
        join(0);
}

示例1:

public class ThreadJoinTest {
    public static void main(String[] args) throws InterruptedException{
        //创建Thread类对象
        Thread t = new Thread(()->{
            for (int i = 1; i <= 5; i++) {
                System.out.println("子线程:" + i);
            }
        });

        //开启子线程
        t.start();

        //子线程加入,使得主线程等待
        t.join();
        for (int i = 1; i <= 5; i++) {
            System.out.println("主线程:" + i);
        }
    }
}

运行结果:

子线程:1
子线程:2
子线程:3
子线程:4
子线程:5
主线程:1
主线程:2
主线程:3
主线程:4
主线程:5

注意:join的意思是加入,子线程调用join()方法后可以理解为把主线程挤掉了。
           ~~~~~~~~~~           等到子线程执行完,主线程才会继续执行。
           ~~~~~~~~~~           比如:在A线程中调用了B线程里的join()方法,A线程就要被挤掉。
           ~~~~~~~~~~           只有等B线程执行完毕之后,A线程才会继续执行。

4.线程休眠

线程休眠就比前面两个例子都好理解,也是代码最少的。
直接调用Thread类里的sleep(long millis)方法就行了。

休眠三秒后打印ok!

public class ThreadSleepTest {
    public static void main(String[] args) throws InterruptedException{
        Thread.sleep(3000);
        System.out.println("ok!");;
    }
}

结果

ok!

5.获取线程实例

获取线程实例,可以分为获取当前线程实例和获取全部线程实例。

1.使用Thread类中的静态方法currentThread()获取当前实例。

public class GetThreadObjectTest {
    public static void main(String[] args) {
        //获取当前线程实例对象
        Thread current = Thread.currentThread();
        
        //打印线程名字
        System.out.println(current.getName());
    }
}

打印结果:

main

2.使用getThreadGroup()方法获取ThreadGroup对象,
调用这个对象里的enmerate(Thread[] list)方法获取全部的实例。

public class GetThreadObjectTest2 {
    public static void main(String[] args) throws InterruptedException{
        Thread t = new Thread(()->{
        });
        t.start();
        ThreadGroup group = Thread.currentThread().getThreadGroup();
        int count = group.activeCount();
        Thread[] list = new Thread[count];
        group.enumerate(list);
        for (Thread thread : list) {
            if (thread != null) {
                System.out.println(thread.getName());
            }
        }
    }
}

以下是在idea中运行的结果:

main
Monitor Ctrl-Break
Thread-0

注意:

  1. ThreadGroup 类中的activeCount()方法是获取的是未进入死亡状态的线程总数。
    这个方法获取的线程总数是动态变化的,因为你不知道其他线程什么时候死亡,只能作为一个约数。
  2. 获取完线程的总数后,用enumerate(Thread[] list)方法获取全部的线程对象。
  3. 获取的对象有可能为null,使用的时候要判断一下,不然有可能null指针异常。

所有的代码都在gitee上,有需要的可以自行获取
gitee链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值