写一个代码,让主线程创建一个新的线程,由新的线程负责完成一系列的运算(比如:1 + 2 + 3 +... + 1000),再由主线程负责获取到最终结果。
但打印结果为 result = 0,略微思考,明白了要让 t 线程先执行完,然后再打印 result。补充,其实如果主线程直接就打印 result,此时得到的结果是啥,其实是无法预期的,由于线程之间的执行顺序不确定,主线程打印的 result 可能是还没有开始计算的初始值0,也可能是过程时候的中间结果,也可能是 t 线程计算完成之后的最终结果。
可以使用 sleep 来等待 t 线程结束,但问题是,不知道 t 线程到底要执行多久。
使用 join() ,就会严格按照 t 线程执行结束来作为等待的条件。什么时候 t 运行结束(计算完毕),什么时候,join 就结束等待。t 运行 1ms,join 就等待 1ms,t 运行 10s,join 就等待 10s,确保 join 之后得到的结果,一定是靠谱的结果。
如果我们要计算到 1 + ... + 100_0000_0000
这样只在一个线程中运算,运算量又非常大,我们就可以搞多个线程,分别运算,每个线程负责算一部分,又可以进一步的提高效率了。
这样就大大节省了时间,提升了效率。(注意:这里计算的时候,每一次结果都是不同的,就涉及到了“线程安全问题”)。
线程的状态
就绪:这个线程随时可以去 CPU 上执行(也包含在 CPU 上执行)
阻塞:这个线程暂时不方便去 CPU 上执行,在 Java 中,针对阻塞状态又做了进一步的细分。
Java 中,线程有如下几种状态:
1.NEW:Thread 对象创建好了,但是还没有调用 start 方法在系统中创建线程。
2.TERMINATED:Thread 对象仍然存在,但是系统内部的线程已经执行完毕了。
3.RUNNABLE:就绪状态,表示这个线程正在 CPU 上执行,或者随时准备就绪可以去 CPU 上执行。
4.TIME_WAITING 指定时间的阻塞,即到达一定时间之后,自动接触阻塞,使用 sleep 会进入这个状态,使用带有超时时间的 join 也会进入这个状态。
5.WAITING 不带时间的阻塞(死等),必须要满足一定的条件,才会解除阻塞。join 或者 wait 都会进入 WAITING。
6.BLOCKED 由于锁竞争引起的阻塞
如果发现某个进程卡住了,就可以使用 jconsole 这样的工具,查看这个进程中的一些重要线程的状态和调用栈,通过状态,就可以判断线程是否阻塞,已经是因为什么原因阻塞的。