Java并发编程序列之线程状态

并发编程序列之线程状态

Hello,你们好,今天开始着手写并发编程序列博客。欢迎你们订阅点赞。谈到并发编程,要谈的东西可就多了,本文做为并发编程序列的第一篇文章,结构以下:java

  1. 线程的建立方式和常见的线程API
  2. 线程的状态
  3. 线程排查工具

1. 线程的建立方式和常见的线程API

  • 直接继承Thread类 略。
  • 实现Runnable接口,传入到Thread中去。略。
  • 经过Callable和Future建立线程,具备返回值:
public class CallableThreadTest implements Callable<Integer> {

    public static void main(String[] args) {
        CallableThreadTest ctt = new CallableThreadTest();
        FutureTask<Integer> ft = new FutureTask<>(ctt);
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " 的循环变量i的值" + i);
            if (i == 20) {
                new Thread(ft, "有返回值的线程").start();
            }
        }
        try {
            System.out.println("子线程的返回值:" + ft.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
    @Override
    public Integer call() throws Exception {
        int i = 0;
        for (; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
        return i;
    }
} 
复制代码
  • 经过Executor线程池技术来启动线程,后期讲线程池时讲。

而后提一下常见的线程API,说下注意点:
算法

  1. Thread的方法为static方法,thread的方法为实例方法。
  2. Thread方法经过实例来调用的效果是同样同样的,千万不要误解。误觉得经过实例调用就是对某个实例的操做。
  3. Thread方法通常的语意就是对"当前代码执行线程"!

Thread.currentThread():获取代码运行位置的当前线程。
thread.isAlive(); 判断某个线程是否存活。
Thread.sleep(); 注意sleep方法是static方法,无论用实例调用,仍是类调用,效果都是同样,让当前执行代码的线程sleep.
顺带说一个问题,咱们在启动线程时,老是调用start方法,start方法的效果就是内部调用了run方法,记得必定不要本身手动调用run方法,由于若是本身调的话,那么run方法内部的Thread类的static方法中的"当前执行线程"的含义就不是子线程了,而是调用线程。
中断相关:
thread.interrupt();将某个线程的中断标志位设置为true.注意,线程并无中断,只是更改了标志位。
Thread.interrupted():判断当前线程是否中断,执行完后,将标志位更改成false,因此连续调用两次,返回值有可能不同。 thread.isInterrupted();判断该对象是不是中断的,不改变标志位。
废弃方法,不要使用:
thread.suspend();
thread.resume();
thread.stop();
编程

2. 线程的状态

Java线程状态图

线程状态 描述
NEW 初始状态,刚建立出来尚未start
RUNNABLE 运行中或者就绪状态.
BLOCKED 阻塞状态。注意只有synchronized关键字的锁才会到BLOCKED状态,JUC的Lock相关的锁是不会到这个状态的。而是进入到WAITING或者TIMED_WAITING状态。由于Lock接口的相关类内部都是使用LockSupport相关的方法
WAITING/TIMED_WAITING 等待状态。
TERMINATED 线程结束

3. 线程排查工具

先说一个概念:线程上下文切换,多线程编程最忌讳的就是线程开的特别多,而后都处于空闲状态(WAITING),这样CPU每次切换过去都又切换走,上下文切换比较频繁,至关耗时。 查看上下文切换频率:
vmstat 1 多线程

通常来讲1000可能是比较正常的。能够考虑使用JUC的Automic包的Cas算法,减小上下文切换。

Jstack使用: 并发

稍微说下,先jstack生成线程dump文件。而后看下有多少线程分别处于什么状态。我这里的都还算正常的。若是有不正常的。打开dump文件好好看看哪里报的问题。
grep java.lang.Thread.State /opt/dump01 | awk '{print $2$3$4$5}' | sort |uniq -c

死锁就更有意思了,当看到BLOCKED比较多时,并且长时间不消下去。那么就要仔细看dump文件了,搜索BLOCKED关键字,而后看是哪里报的BLOCKED,看代码,检查代码的死锁。须要注意的是,若是是使用JUC的Lock形成的死锁,那么久要检查WAITING状态下的代码了
其次Jstack -l pid 能够打印出锁相关的信息。系统也能够自动帮咱们侦测死锁。相似于Found 1 deadlock这样的关键字。
死锁最有效的避免方法就是使用tryLock(time)了,拿不到锁就返回。不要拿了。ide

结语

好了,打完收工。
下期预告:
线程间通信,synchronized关键字,volatile关键字.工具

相关文章
相关标签/搜索