美文网首页
java多线程的那些事

java多线程的那些事

作者: 知名乐天 | 来源:发表于2020-03-30 00:05 被阅读0次

引言

在平时的工作中,经常能碰到程序需要对大量的数据进行相同的操作,如果只是传统的单线运行,无疑会碰到执行时间过长。尤其是在处理一些即时性要求较高的数据的时候,处理太慢无疑就是事故级别的存在了。因此,这个时候,我们就可以考虑多线程。

为什么要使用多线程

没有什么问题是多线程解决不了的,如果有,就再起一个线程。

线程作为计算机调度资源的基本单位,使用多线程,可以充分利用CPU资源,避免由于某个任务执行时间过长而导致后续任务一直处于等待的情况。

线程的运行周期:

线程总共有五种状态:

线程的生命周期.png

其中:

  1. 阻塞存在三种情况:
  • 被阻塞: 常见于抢不到锁而被堵塞;
  • 等待: 线程等待另一个线程通知线程调度;
  • 计时等待: 线程只等待一定的时间,超时就不再等待;
  1. 线程死亡:
  • 自然终止: 当线程自动执行结束之后,线程资源被回收;
  • 异常终止: 线程被强行通过interrupt等操作中断;

那么在java中,如何新起一个线程呢?

java的多线程

1, Thread类;
2, Runnable接口
3, Future 和 Callable

接下来我们详细介绍下Thread类

Java多线程之Thread类详解(java.lang.Thread)

构造方法:
public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize, boolean inheritThreadLocals) {
        init(group, target, name, stackSize, null, inheritThreadLocals);
    }

参数的解析:

  1. group: 线程组,即new Thread 的该线程的ThreadGroup
  2. target: 一个Runnable的任务
  3. stackSize:该线程执行过程中的最大的栈深度;
  4. inheritThreadLocals : 是否继承原有父线程的变量,如果设置为true的话,会通过用一个ThreadLocalMap将变量存储;

start 方法

 public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

其中 threadStatus 表明线程的状态,各个值的含义为:

  • 0: NEW
  • 1: RUNNABLE
  • 2: BLOCKED
  • 3: WAITING
  • 4:TIMED_WAITING
  • 5: TERMINATED

start0() : 为一个native方法,该方法作用为产生新线程并调用run方法;

run方法:执行传入的Runnable实例中的run方法

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

关于Thread类其他重要的方法

native方法:
  1. registerNative():将指定的方法,如start0,sleep,yield等本地方法绑定到函数中;
  2. sleep() :使该线程陷入阻塞的状态;
  3. yield():该方法在于将本身的状态改为就绪态;
  4. 备注: yield 和sleep 是有区别的yield是重新到就绪状态,而sleep是进入到阻塞的状态

其他非native方法

  • exit(): 调用 threadTerminated 方法,将其他属性都置为null
  • interrupt(): 通过(interrupt0)修改中断标识位,当出现阻塞的时候,线程就会抛出 InterruptedException;
  • join():调用的线程等待被调用实例线程一定时间(传参数)或者一直等待到结束;

下面给出一些简单的例子来进行调用:

public·class·MyThread·extends ·Thread {

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            public void run() {
                Long id = currentThread().getId();
                try {
                    System.out.println(getTime() +":开始的线程id:" + id);
                    Thread.sleep(5000);
                    System.out.println(getTime() + ":结束的线程id:" + id);
                } catch (InterruptedException exp) {
                    System.out.println(getTime() + ":中断的线程id:" + id);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {

                }
            }
        };
        MyThread testThread1 = new MyThread(runnable);
        testThread1.start();

        MyThread testThread2 = new MyThread(runnable);
        testThread2.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(getTime()+":主线程执行完毕");
    }

    public MyThread(Runnable target) {
        super(target);
    }
    
    public static String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(new Date());
    }
}

/**
执行的结果为:
开始的线程id:12
开始的线程id:13
主线程执行完毕
结束的线程id:13
结束的线程id:12
*/

interrupt方法尝试:

代码片段如下:
        testThread2.start();
        testThread1.interrupt();
        try {

输出结果如下:
2020-03-29 17:32:02:开始的线程id:13<br>
2020-03-29 17:32:02:开始的线程id:12<br>
2020-03-29 17:32:02:中断的线程id:12<br>
2020-03-29 17:32:03:主线程执行完毕 <br>
2020-03-29 17:32:07:结束的线程id:13<br>

分别尝试使用:join方法

  1. 添加 testThread1.join(1000); 执行结果如下:
代码片段如下:
            testThread1.join(1000);
            Thread.sleep(2000);
 2020-03-29 17:40:04:开始的线程id:13
 2020-03-29 17:40:04:开始的线程id:12
 2020-03-29 17:40:07:主线程执行完毕
 2020-03-29 17:40:09:结束的线程id:13
 2020-03-29 17:40:09:结束的线程id:12
  1. 添加 testThread2.join(); 执行结果如下:
代码片段如下:
            testThread2.join(1000);
            Thread.sleep(2000);
2020-03-29 17:41:00:开始的线程id:13
2020-03-29 17:41:00:开始的线程id:12
2020-03-29 17:41:05:结束的线程id:12
2020-03-29 17:41:05:结束的线程id:13
2020-03-29 17:41:07:主线程执行完毕

至此,我们可以看到,利用Thread新起一个线程是如此的简便。因此,下次碰到多任务的时候,不要再用线性执行的方式了,利用多线程的技术,让你的程序效率翻倍吧。

当然,使用多线程固然会加快速度,但是一味的增加线程数是否真的高效呢?其实不是的,期间涉及到线程的调度开销,以及多线程开发中存在着线程安全的问题。因此,如何优雅的利用多线程开发,期待下次文章吧。

相关文章

  • java多线程的那些事

    引言 在平时的工作中,经常能碰到程序需要对大量的数据进行相同的操作,如果只是传统的单线运行,无疑会碰到执行时间过长...

  • 带你搞懂Java多线程(五)

    带你搞懂Java多线程(一)带你搞懂Java多线程(二)带你搞懂Java多线程(三)带你搞懂Java多线程(四) ...

  • 带你搞懂Java多线程(六)

    带你搞懂Java多线程(一)带你搞懂Java多线程(二)带你搞懂Java多线程(三)带你搞懂Java多线程(四)带...

  • Java多线程目录

    Java多线程目录 Java多线程1 线程基础Java多线程2 多个线程之间共享数据Java多线程3 原子性操作类...

  • Java相关面试问题

    线程,多线程,线程池的那些事 Java中的线程的生命周期大体可分为5种状态:新建、可运行、运行、阻塞、死亡。 1、...

  • 多线程编程那些事

    多线程编程那些事 标签:HPC、多线程、JMM、Volatile、锁、CPU多核构架、Happens before...

  • 5月份第一周学习安排

    学习内容: java多线程及线程同步的方法(使用) java多线程各种同步方法的原理和优缺点 java多线程设计模...

  • Java多线程4-ThreadLocal的那些事

    声明:原创文章,转载请注明出处。https://www.jianshu.com/p/6341cfa5c3cd 一、...

  • 关于java多线程和并发的那些事

    java编程中的技能树有很多种,但是总体上都是围绕着数据变来变去的,其中并发技能也是类似。 场景 假想一下当你要处...

  • android 多线程 — 线程的面试题和答案

    这里都是我从各个地方找来的资料,鸣谢: Java多线程干货系列—(一)Java多线程基础 JAVA多线程和并发基础...

网友评论

      本文标题:java多线程的那些事

      本文链接:https://www.haomeiwen.com/subject/vzguuhtx.html