在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表达式
如果我们想中断一个在运行的线程,就可用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();
}
}
线程正在运行中...
线程正在运行中...
线程正在运行中...
线程正在运行中...
线程正在运行中...
...
...
...
线程被中断!
interrupt()
方法后,Thead.interrupted()
的返回值变为true
。睡眠状态
变为可运行状态
Thead.interrupted()
的返回值改为又改为false
。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)
由于多个线程之间执行顺序是随机的,无法确定线程的执行顺序。
但可以通过人工干预使得线程线程之间相对有序。
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线程才会继续执行。
线程休眠就比前面两个例子都好理解,也是代码最少的。
直接调用Thread
类里的sleep(long millis)
方法就行了。
休眠三秒后打印ok!
public class ThreadSleepTest {
public static void main(String[] args) throws InterruptedException{
Thread.sleep(3000);
System.out.println("ok!");;
}
}
结果
ok!
获取线程实例,可以分为获取当前线程实例和获取全部线程实例。
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
注意:
ThreadGroup
类中的activeCount()
方法是获取的是未进入死亡状态的线程总数。enumerate(Thread[] list)
方法获取全部的线程对象。null
,使用的时候要判断一下,不然有可能null
指针异常。所有的代码都在gitee上,有需要的可以自行获取
gitee链接