Java多线程基础(一)Thread 类 API 详解

    介绍 Thread 类的 核心API,在使用这些 API 的过程中,会出现一些意想不到的情况,其实这也是多线程不可预知性的一个体现,学习并掌握这些常见 case,也就掌握了多线程开发的命脉与特点。

 

    概览:

    -Thread 类与 Runnable 接口介绍

    -getId()方法    线程唯一标识 ID

    -currentThread()方法    

    -isAlive()方法

    -sleep()方法

    -yield()方法    

    -StackTraceElement[] getStackTrace()方法

    -static void dumpStack()方法

    -static Map getAllStackTraces()方法

    -设置线程优先级

    -setDaemon()方法 守护线程

 

1.  -Thread 类与 Runnable 接口介绍

    Thread 类的声明结构:

    public class Thread implements Runnable

    构造函数:

    Thread()

    Thread(Runnable target)

    Thread(Runnable target, String name) //分配新的 Tread 对象,并将 target 作为其运行对象,name 为其线程名称

    Thread(String name)

    Thread(ThreadGroup group, Runnable target)

    Thread(ThreadGroup group, Runnable target, String name)

    Thread(ThreadGroup group, Runnable target, String name, Long stackSize)

    Thread(ThreadGroup group, String name)

    实现多线程编程主要有两种方式 :一种是继承Thread 类,另一种是实现 Runnable 接口。

    使用这两种方式创建线程的功能是一样的,没有本质的区别。使用继承 Thread 类创建新线程时,最大的局限是 不支持多继承。

   示例1:

    使用第一种方式创建一个多线程类:

 

public class MyThread extends Thread {
​
    @Override
    synchronized public void run() {
        super.run();
        System.out.println("print MyThread done .");
    }
}

     

    运行:

 

public class Run {
​
    public static void main(String[] args) {
        Thread myThread = new MyThread();
        myThread.start();           // a
        System.out.println("run done");  // b
    }
}

    运行结果:

    可以看到, 虽然从代码顺序上看步骤 a 先执行,但是结果b 比 a先执行完。

   这是因为 start()方法的执行比较耗时,底层有如下过程:

    1)通过 JVM 告诉操作系统创建线程 Thread

    2)操作系统开辟内存并调用系统函数创建 Thread 线程对象

    3)操作系统对 Thread 线程对象进行调度,以确定执行时机

    4)Thread 在操作系统中被成功执行

 

    注意: 如果在 run 类中直接调用 myThread.run()方法,就不是异步执行了,而是同步执行,此线程对象不交给底层的“线程规划器”处理,而是有 main 主线程来调用,也就是必须等 run()方法中的代码执行完毕后才可以执行后面的代码。如下所示:

    

 

public class Run {
​
    public static void main(String[] args) {
        Thread myThread = new MyThread();
        myThread.run();
        System.out.println("run done");
    }
​
}

 

Java多线程基础(一)Thread 类 API 详解_第1张图片

    示例2:

 

public class Run {
​
    public static void main(String[] args) {
        
        Thread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
        System.out.println("run done");
    }
}

 

Java多线程基础(一)Thread 类 API 详解_第2张图片

    

当使用构造方法

    -Thread(Runnable target)

    查看源码 可知,其内部流程为:

 

@override
public void run() {
    if (target != null) {
        target.run();
    }
}
     

 

2. getId() 方法

    获取线程的唯一标识。

 

public class Run {
​
    public static void main(String[] args) {
​
        System.out.println(Thread.currentThread().getName());
        System.out.println(Thread.currentThread().getId());
    }
}

 

Java多线程基础(一)Thread 类 API 详解_第3张图片

 

 

3. currentThread()方法

    currentThread()方法可以返回代码段正在被哪个线程调用。

 

public class MyThread extends Thread {
​
    MyThread() {
        System.out.println("in 构造方法, 当前调用线程名 :" + Thread.currentThread().getName());
    }
    @Override
    synchronized public void run() {
        super.run();
        System.out.println("in run()方法, 当前调用线程名:" + Thread.currentThread().getName());
    }
}

 

public class Run {
​
    public static void main(String[] args) {
​
        Thread myThread = new MyThread();
        myThread.start();
    }
}

Java多线程基础(一)Thread 类 API 详解_第4张图片

 

4. isAlive()方法

    判断当前线程是否存活

    

5. sleep()方法

    sleep(long millis) 让线程休眠

 

6. yield()方法

    yield()方法的作用是放弃当前的 cpu 资源,让其它任务去占用 cpu 执行时间,放弃时间不确定,有可能刚放弃又马上获得时间片。

    Thread.yield();

7. StackTraceElement[] getStackTrace()方法

    返回一个表示该线程堆栈跟踪元素数组。如果该线程尚未启动或已经终止,则该 方法将返回一个 零长度数组。如果返回的数组不是零长度的,则第一个元素表示堆栈顶,它是该数组中最新的方法调用。最后一个元素表示堆栈底,是该数组中最旧的方法调用。

 

package com.app.main.multithread;
​
/**
 * Created with IDEA
 * author:Dingsheng Huang
 * Date:2019/6/28
 * Time:下午5:38
 */
public class Test1 {
​
    public void a() {
        b();
    }
    public void b() {
        c();
    }
    public void c() {
        StackTraceElement[] arr = Thread.currentThread().getStackTrace();
        String separator = "==";
        if (arr != null) {
            for (int i = 0; i < arr.length; i++) {
                StackTraceElement item = arr[i];
                System.out.println(item.getClassName() + separator + item.getFileName() +separator + item.getMethodName() + separator + item.getLineNumber());
            }
        }
    }
​  
  public static void main(String[] args) {
        Test1 test1 = new Test1();
        test1.a();
    }
}

运行结果:输出了当前线程的堆栈跟踪信息

Java多线程基础(一)Thread 类 API 详解_第5张图片

 

8. static void dumpStack()方法

    该方法仅用于调试,将当前线程的堆栈跟踪信息输出至标准错误流。

 

package com.app.main.multithread;
​
/**
 * Created with IDEA
 * author:Dingsheng Huang
 * Date:2019/6/28
 * Time:下午5:38
 */
public class Test1 {
​
    public void a() {
        b();
    }
    public void b() {
        c();
    }
    public void c() {
        Thread.dumpStack();
    }
 public static void main(String[] args) {
        Test1 test1 = new Test1();
        test1.a();
    }
}
​
   

运行结果:

 

Java多线程基础(一)Thread 类 API 详解_第6张图片

 

9. static Map getAllStackTraces()方法

    返回所有活动线程的堆栈跟踪的一个映射。映射键是线程,值是一个 StackTraceElement数组 , 该数组表示相应 Thread 的堆栈存储。

    调用该方法的同时,线程可能也在执行。每个线程的堆栈跟踪仅代表一个快照。

 

10. 设置线程优先级

    在操作系统中,线程可以划分优先级,高优先级的线程获得更多的时间片。再 java 中,线程的优先级分为1~10的等级,如果优先级小于1或者大于10,会抛出 IllegalArgumentException()

    继承性:A 启动线程 B,则 B 线程的优先级与 A 一样。

    不确定性:线程优先级与执行顺序无关,这两者没有依赖关系,它们具有不确定性、随机性

    用法:thread.setPriority(1);

 

11. setDaemon() 设置守护线程

    Java 中有两种行程:一种是用户线程,也称非守护线程;另一种是守护线程。

    守护线程:一种特殊的线程,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程时垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。

    用法: thread.setDaemon(true);

    

 

你可能感兴趣的:(Java基础,Java并发)