• Hello,Thread


    创建线程的三种方法,线程的生命周期,sleep,yield,join,wait 和notify,线程组,守护线程,线程的优先级

    如何创建线程

    Java 中创建线程的方法有三种:

    1. 继承 Thread 类创建线程

    新建一个类继承 Thread 类,并重写 Thread 类的 run() 方法。
    创建 Thread 子类的实例。
    调用该子类实例的 start() 方法启动该线程。

    代码举例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class HelloThread1 {
    static class ThreadDemo extends Thread {
    @Override
    public void run() {
    System.out.println("Hello Thread");
    }
    }
    public static void main(String[] args) {
    ThreadDemo threadDemo = new ThreadDemo();
    threadDemo.start();
    }
    }

    2.实现 Runnable 接口创建线程:

    创建一个类实现 Runnable 接口,并重写该接口的 run() 方法。
    创建该实现类的实例。
    将该实例传入 Thread(Runnable r) 构造方法中创建 Thread 实例。
    调用该 Thread 线程对象的 start() 方法。

    代码举例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class HelloThread1 {
    static class ThreadDemo extends Thread {
    @Override
    public void run() {
    System.out.println("Hello Thread");
    }
    }
    public static void main(String[] args) {
    ThreadDemo threadDemo = new ThreadDemo();
    threadDemo.start();
    }
    }
    1. 使用 Callable 和 FutureTask 创建线程:

    创建一个类实现 Callable 接口,并重写 call() 方法。
    创建该 Callable 接口实现类的实例。
    将 Callable 的实现类实例传入 FutureTask(Callable callable) 构造方法中创建 FutureTask 实例。
    将 FutureTask 实例传入 Thread(Runnable r) 构造方法中创建 Thread 实例。
    调用该 Thread 线程对象的 start() 方法。
    调用 FutureTask 实例对象的 get() 方法获取返回值。

    代码举例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class HelloThread3 {
    static class ThreadDemo implements Callable<String> {
    @Override
    public String call() {
    System.out.println("Hello Thread");
    return "Callable return value";
    }
    }
    public static void main(String[] args) {
    ThreadDemo threadDemo = new ThreadDemo();
    FutureTask<String> futureTask = new FutureTask<String>(threadDemo);
    Thread thread = new Thread(futureTask);
    thread.start();
    try {
    System.out.println(futureTask.get());
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }


    线程的生命周期

    关于Java中线程的生命周期,首先看一下下面这张图:

    上图中基本上囊括了Java中多线程各重要知识点。掌握了上图中的各知识点,Java中的多线程也就基本上掌握了。


    线程的基本状态

    新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

    就绪状态(Runnable):当调用方法t.start()时,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;同样还有几种情况会进行就绪状态,请参见上图。

    运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

    阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:请参见上图。

    死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。


    线程的基本操作

    sleep:使当前线程休眠指定毫秒

    yield:使当前线程让出CPU,从运行状态转到可运行状态。注意仅仅是让出,让出之后也会加入到抢占资源的队伍中。

    join:把指定的线程加入到当前线程,比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B

    线程停止:
    Thread本身提供了一个stop方法,但是这个不推荐使用。因为使用stop的时候会暴力终止线程,从而造成数据不一致。
    优雅的停止线程的代码举例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class StopThread {
    static class ThreadDemo extends Thread {
    volatile boolean stopMe = false;
    public void stopMe(){
    this.stopMe=true;
    }
    @Override
    public void run() {
    while (true) {
    if (stopMe) {
    System.out.println("程序结束");
    break;
    }
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }
    public static void main(String[] args) {
    ThreadDemo threadDemo = new ThreadDemo();
    threadDemo.start();
    threadDemo.stopMe();
    }
    }

    以一个volatile修饰的变量stopMe来控制线程的停止。

    线程中断:

    线程中断的相关方法分别是这三个

    1
    2
    3
    public void interrupt() ; //中断线程
    public boolean isInterrupted(); //判断线程是否被中断
    public static boolean interrupted(); //判断线程是否被中断,并清除当前中断状态

    线程中断的代码举例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class InterruptThread {
    static class ThreadDemo extends Thread {
    @Override
    public void run() {
    while (true) {
    if (Thread.currentThread().isInterrupted()) {
    System.out.println("程序结束");
    break;
    }
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }
    public static void main(String[] args) {
    ThreadDemo threadDemo = new ThreadDemo();
    threadDemo.start();
    threadDemo.interrupt();
    }
    }

    wait 和notify
    这两个方法是JDK为了支持多线程之间的协作而提供的。
    当在线程A中调用了obj.wait()方法时,线程A会停止执行进入等待状态。直到其他线程调用obj.notify()时才会进入阻塞状态继而等待获取锁。
    请看下方示例代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    public class WaitNotifyThread {
    public static Object obj = new Object();

    static class WaitThreadDemo extends Thread {
    @Override
    public void run() {
    synchronized (obj) {
    try {
    System.out.println("WaitThread wait,time=" + System.currentTimeMillis());
    obj.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("WaitThread end,time=" + System.currentTimeMillis());
    }
    }
    }

    static class NotifyThreadDemo extends Thread {
    @Override
    public void run() {
    synchronized (obj) {
    System.out.println("NotifyThread notify,time=" + System.currentTimeMillis());
    obj.notify();
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("NotifyThread end,time=" + System.currentTimeMillis());
    }
    }
    }

    public static void main(String[] args) {
    WaitThreadDemo waitThreadDemo = new WaitThreadDemo();
    NotifyThreadDemo notifyThreadDemo = new NotifyThreadDemo();
    waitThreadDemo.start();
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    notifyThreadDemo.start();
    }
    }

    在上方的代码中,Wait线程会首先获取到obj的锁,当它执行wait方法时就会释放obj的锁并进入等待状态。这个时候Notify线程可以获取到obj的锁,并且唤醒Wait线程,但是因为此时Notify线程是睡眠了2秒钟之后才释放的obj的锁,所以Wait线程获取锁的时候Notify线程已经执行完毕了。
    此程序的运行结果:

    1
    2
    3
    4
    WaitThread wait,time=1553088237753
    NotifyThread notify,time=1553088237862
    NotifyThread end,time=1553088239867
    WaitThread end,time=1553088239867

    suspen和resume
    它们两个的功能是挂起线程和继续执行,被suspen挂起的线程必须被resume唤醒才可以继续执行。乍看起来 可以实现wait和notify的功能,不过我可不推荐你使用它们,和wait之后会释放锁不同,suspen挂起之后依然会持有锁,这个可就非常危险了。

    线程组
    在一个系统中如果线程数量众多而又功能比较一致,就可以把这些线程放到一个线程组里。
    线程组示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class ThreadGroupDemo {
    static class ThreadDemo extends Thread {
    @Override
    public void run() {
    while (true){
    System.out.println("I am "+Thread.currentThread().getThreadGroup().getName()+"-"+Thread.currentThread().getName());
    try {
    sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }
    public static void main(String[] args) {
    ThreadGroup threadGroup=new ThreadGroup("groupDemo");
    Thread t1=new Thread(threadGroup,new ThreadDemo(),"t1");
    Thread t2=new Thread(threadGroup,new ThreadDemo(),"t2");
    t1.start();
    t2.start();
    }
    }

    守护线程
    在线程的世界里,由我们自己创建的线程叫用户线程。而一些系统创建的线程,如垃圾回收线程等被称之为守护线程,如果想要把一个用户线程设置为守护线程可以在线程的调用线程的start方法前设置线程的daemon属性为true;

    1
    t1.setDaemon(true);

    当一个程序中只有守护线程的时候这个程序也就要结束了。

    线程的优先级

    Java中的线程可以有自己的优先级,优先级高的线程在进行资源抢占的时候往往会更有优势。线程饥饿现象就是由于线程的优先级低无法抢占资源而引起的。
    在Java中线程的优先级可以设置的范围是1到10之间,数字越大优先级越高。Java线程创建默认的优先级是5,我们可以线程start之前通过如下方式设置线程的优先级。

    1
    t1.setPriority(1);

    本文所有源码https://github.com/shiyujun


  • 相关阅读:
    Antlr与Regex
    c_str()
    C++ 友元
    C++ 操作符重载
    Remote 'attachhome' failed on nodes:XXX
    RAC安装GI时运行root.sh脚本结果
    clscfg.bin: error while loading shared libraries: libcap.so.1:
    RAC安装重新运行root.sh
    libXext.so.6 libXp.so.6 libXt.so.6 is needed by openmotif21-2.1.30-11.el7.i686
    向数据库中导入AWR数据
  • 原文地址:https://www.cnblogs.com/zhixiang-org-cn/p/10576170.html
Copyright © 2020-2023  润新知