Java线程中常用的方法

方法名作用
start()让线程进入就绪状态,每个线程对象的start方法只能调用一次
run()新线程启动后会调用的方法
join()等待线程运行结束
getId()获得线程长整型的id
getName()获取线程名
getPriority()获得线程优先级
setPriority()修改线程优先级
getState()获取线程状态
isInterrupted()判断当前线程是否被打断(不会清除打断标记)
isAlive()线程是否存活
interrupt打断线程
interrupted()判断当前线程是否被打断(会清除打断标记)
currentThread()获取当前正在执行的线程
sleep()让当前执行的线程休眠
yield()提示线程调度器让出当前线程对cpu的使用

1、 run 和 start

package com.java_thread.often_methods;

/**
 * run 和 start
 */

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.RunAndStart")
public class RunAndStart {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                log.debug("running...");
            }
        };

        //thread.run其实还是主线程,没有起到异步的作用
        thread.run();

        thread.start();

    }
}

在这里插入图片描述

2、getState

package com.java_thread.often_methods;

/**
 * getState
 */

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.GetState")
public class GetState {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                log.debug("running...");
            }
        };

        //尚未启动之前,线程的状态
        System.out.println(thread.getState());

        //启动之后,线程的状态
        thread.start();
        System.out.println(thread.getState());
    }
}

在这里插入图片描述

3、sleep 和 yield

package com.java_thread.often_methods;

/**
 * sleep 和 yield
 *
 * sleep:
 * 1、调用sleep会让当前线程从running进入timed waiting状态
 * 2、其他线程可以使用interrupt方法打断正在睡眠的线程,这时线程会抛出InterruptedException
 * 3、睡眠结束后的线程未必会立刻得到执行
 * 4、建议用TimeUnit的sleep代替Thread的sleep来获得更好的可读性
 *
 * yield:
 * 1、调用yield会让当前线程从Running进入runnable就绪状态,然后调度执行其它线程(礼让)
 * 2、具体的实现依赖于操作系统的任务调度器(礼让未必成功)
 */
public class SleepAndYield {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000 * 2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        thread.start();

        System.out.print("调用sleep方法后,线程从运行变为等待: " + thread.getState() + " -> ");

        Thread.sleep(500);

        System.out.print(thread.getState() + "\n");

        Thread.sleep(500);

        thread.interrupt();

        System.out.println("调用interrupt后,抛出异常");

    }
}

在这里插入图片描述

4、setPriority 和 getPriority

package com.java_thread.often_methods;

/**
 * setPriority 和 getPriority
 *
 * 线程优先级:
 * 1、线程优先级会提示调度器有限调度该线程,但它仅仅只是一个提示,调度器可以忽略它
 * 2、如果cpu很忙,那么优先级高的线程会获得更多的时间片,但cup闲时,优先级几乎没有任何作用
 */
public class SetPriorityAndGetPriority {
    public static void main(String[] args) {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                int i = 0;
                while (true) {
                    System.out.println("i = " + (i++));
                }
            }
        };

        Thread t2 = new Thread() {
            @Override
            public void run() {
                int j = 0;
                while (true) {
                    System.out.println("j = " + (j++));
                }
            }
        };

        //越高的优先级被执行的可能越大(不是一定,和cpu的调度有关)
        t1.setPriority(10);
        t1.start();
        
        t2.setPriority(1);
        t2.start();

    }
}

5、join

package com.java_thread.often_methods;

import java.awt.*;
import java.util.concurrent.TimeUnit;

/**
 * join
 *
 */
public class Join {
    public static int i = 0;
    public static void main(String[] args) throws InterruptedException {
        test();
    }

    private static void test() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println("线程t1开始休眠1秒");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程t1已经醒了");
            i = 10;
        });

        t1.start();
        //等待t1线程运行结束,如果没有t1.join()那么i的值为0,有的话为10
        t1.join();
        System.out.println("i的结果为: " + i);
    }
}

没有t1.join()的情况:

在这里插入图片描述

有t1.join()的情况

在这里插入图片描述

还可以设置时间参数,当时间达到后,线程还没有运行完的话,就不等了,程序继续向下运行

6、interrupt

打断sleep、wait、join的线程

  • 打断阻塞的线程,以sleep为例,会清空打断状态
package com.java_thread.often_methods;

/**
 * interrupt
 */
public class Interrupt {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");

        thread.start();
        thread.interrupt();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2imzIKvl-1607655939415)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201130010936533.png)]

像wait、sleep、join等被打断后,其打断标志会置为false

package com.java_thread.often_methods;

/**
 * interrupt
 */
public class Interrupt {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");

        thread.start();
        Thread.sleep(500);
        thread.interrupt();
        System.out.println("打断标志: " + thread.isInterrupted());
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X2blEjnh-1607655939417)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201130011535284.png)]

  • 打断正常运行的线程,不会清空打断标志

    Thread thread2 = new Thread(() -> {
        while (true) {
    
        }
    }, "t2");
    
    thread2.start();
    Thread.sleep(1000);
    thread2.interrupt();
    System.out.println("打断标志: " + thread2.isInterrupted());
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3jIuAqy0-1607655939419)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201130012156515.png)]

打断正常运行的线程,不会让线程停止运行,但是可以通过下面方式来使被打断的线程停止运行

Thread thread2 = new Thread(() -> {
    while (true) {
        boolean interrupted = Thread.currentThread().isInterrupted();
        if (interrupted) {
            break;
        }
    }
}, "t2");

7、两阶段终止模式

两阶段终止模式:在一个线程t1中如何优雅的终止线程t2,这里的优雅指的是给t2一个料理后事的机会

7.1 错误思路
  • 使用线程对象的stop方法停止线程

    stop方法会真正杀死线程,如果这是线程锁住了共享资源,那么当它被杀死后,就再也没有机会释放锁,其他线程将永远无法获取锁

  • 使用System.exit(int) 方法停止线程

    目的仅是停止一个线程,但这种做法会让整个程序都停止

7.2 正确思路

package com.java_thread.often_methods;

/**
 * 两阶段终止模式
 */
public class TwoPhaseTermination {
    private Thread monitor;

    //启动监控线程
    public void start() {
        monitor = new Thread(() -> {
            while (true) {
                Thread current = Thread.currentThread();
                if (current.isInterrupted()) {
                    System.out.println("料理后事");
                    break;
                }
                try {
                    //1、如果处在睡眠转态被打断,那么会执行catch块中的current.interrupt(),重新设置打断标志
                    Thread.sleep(1000);
                    //2、如果处于没有睡眠的时候被打断,那么打断标志还是true
                    System.out.println("执行监控");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //重新设置打断标志变为true
                    current.interrupt();
                }
            }
        });

        monitor.start();

    }

    public void stop() {
        monitor.interrupt();
    }
}

class Test {
    public static void main(String[] args) throws InterruptedException {
        TwoPhaseTermination t = new TwoPhaseTermination();
        t.start();

        Thread.sleep(3500);
        t.stop();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yuGg8X2z-1607655939421)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201130023251473.png)]

总结:初始打断标记为true,调用打断方法interrupt()执行打断操作,如果被打断的是没有睡眠的线程,那么打断标记还是true,如果是像wait、sleep、join等被打断后,其打断标志会置为false。
isInterrupted()可以查看当前的打断标记,但是不会重新设置打断标记。
interrupted()会重新设置打断标记

8、打断park线程

当线程执行到LockSupport时就会停止执行,可以通过下面方式来打断park线程

package com.java_thread.often_methods;

import java.util.concurrent.locks.LockSupport;

/**
 * 打断park线程
 */
public class park {
    public static void main(String[] args) throws InterruptedException {
        test();
    }

    private static void test() throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("park...");
            LockSupport.park();
            System.out.println("unpark...");
        },"t1");

        thread.start();

        Thread.sleep(1);
        thread.interrupt();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ct5Sqi1n-1607655939422)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201130130410007.png)]

但是当再次执行park时,发现不起作用

Thread thread = new Thread(() -> {
    System.out.println("park...");
    LockSupport.park();
    System.out.println("unpark...");
    LockSupport.park();
    
},"t1");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iDaREJnP-1607655939424)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201130130515019.png)]

此时可以设置重新设置打断标记来使其发生变化

Thread thread = new Thread(() -> {
    System.out.println("park...");
    LockSupport.park();
    System.out.println("unpark...");
    Thread.interrupted();
    LockSupport.park();

},"t1");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3XaVn1q-1607655939425)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201130130631835.png)]

从上图可以发现,程序一直运行在第二次设置LockSupport.park()的位置

9、不推荐使用的方法

还有一些不推荐使用的方法,这些方法已经过时,容易破坏同步代码块,造成线程死锁

方法名功能说明
stop()停止线程运行
suspend()挂起(暂停)线程运行
resume()恢复线程运行

10、主线程和守护线程

默认情况下,Java进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程

,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制执行结束。

package com.java_thread.often_methods;

/**
 * 守护线程
 */
public class DaemonThread {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
            }
            System.out.println("t1线程结束");
        },"t1");

        thread.setDaemon(true);
        thread.start();

        Thread.sleep(1000);
        System.out.println("主线程结束");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vYK3KJRP-1607655939426)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201130132150219.png)]

从上可以发现,t1线程没有执行结束,但是程序的运行还是结束了。说明的查询的运行是和守护线程的运行是否完成没有关系的。

注意:

  • 垃圾回收线程就是一种守护线程
  • Tomcat中的Acceptor和Poller线程都是守护线程,所以Tomcat接收到shutdown命令后,Tomcat不会等待他们完成之后再关闭。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值