/**
* @description: Thread 创建线程
* @author: teago
* @time: 2020/5/16 08:39
*/
@Slf4j(topic = "Example1")
public class Example1 {
public static void main(String[] args) {
Thread createThread = new Thread(() -> {
log.debug("thread mode create thread");
});
createThread.start();
}
}
把【线程】和【任务】(要执行的代码)分开
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
/**
* @description: Runnable 创建线程
* @author: teago
* @time: 2020/5/16 08:39
*/
@Slf4j
public class Example2 {
public static void main(String[] args) {
Runnable runnable = () -> log.debug(Thread.currentThread().getName());
Thread thread = new Thread(runnable);
thread.start();
}
}
分析Thread的源码,理清它与Runnable的关系
小结:
FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况,线程阻塞等待task执行完毕的结果。
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @description: FutureTask配合Thread
* @author: teago
* @time: 2020/5/16 08:39
*/
@Slf4j
public class Example3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(() -> "futureTask");
Thread thread = new Thread(futureTask);
thread.setName("futureTask mode create thread ");
thread.start();
thread.join();
// 主线程阻塞,同步等待 task 执行完毕的结果
log.debug(futureTask.get());
}
}
主要是理解:
package com.bloom.concurrent.three;
import java.util.concurrent.TimeUnit;
/**
* @description:
* @author: teago
* @time: 2020/5/16 08:53
*/
public class Example4 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true){
System.out.println("test jconsole use");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t4");
thread.start();
}
}
运行结果:
ps -ef
查看所有进程ps -fT -p <PID>
查看某个进程(PID)的所有线程kill
?杀死进程top
按大写 H 切换是否显示线程top -H -p <PID>
查看某个进程(PID)的所有线程package com.bloom.concurrent.three;
import java.util.concurrent.TimeUnit;
/**
* @description:
* @author: teago
* @time: 2020/5/16 08:53
*/
public class Example4 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true){
System.out.println("test jconsole use");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t4");
thread.start();
}
}
java -Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false Example4
controlRole 1234
chmod -R 600 jmxremote.password
chmod -R 600 jmxremote.access
再次运行,结果如下所示:
总结:
java -Djava.rmi.server.hostname=`ip地址`
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=`连接端口`
-Dcom.sun.management.jmxremote.ssl=是否安全连接
-Dcom.sun.management.jmxremote.authenticate=是否认证 java类
如果要认证访问,还需要做如下步骤:
Java Virtual Machine Stacks (Java虚拟机栈)
我们都知道JVM中有堆、栈、方法区所组成,其中栈内存是给谁用的呢?其实就是线程,每个线程启动后,虚拟机都会为其分配一块栈内存。
package com.bloom.concurrent.three;
/**
* @description: Debug方式演示栈帧的调用关系
* @author: teago
* @time: 2020/5/16 09:06
*/
public class TestFrames {
public static void main(String[] args) {
method1(10);
}
private static void method1(int x) {
int y = x + 1 ;
Object m = method2();
System.out.println(m);
}
private static Object method2() {
Object n = new Object();
return n ;
}
}
因为以下一些原因导致CPU不再执行当前的线程,转而执行另一个线程的代码:
当Context Switch发生时,需要由操作系统保存当前线程的状态信息,并恢复另一个线程的状态,Java中对应的概念就是程序计数器(Program Counter Register),它的作用是记住下一条JVM指令的执行地址,是线程私有的。
方法名 | static | 功能说明 | 注意 |
---|---|---|---|
start() | 启动一个新线程,在新的线程运行 run 方法中的代码 | start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现 IllegalThreadStateException | |
run() | 新线程启动后会调用的方法 | 如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法,否则默认不执行任何操作。但可以创建 Thread 的子类对象,来覆盖默认行为 | |
join() | 等待线程运行结束 | ||
join(long n) | 等待线程运行结束,最多等待 n 毫秒 | ||
getId() | 获取线程长整型的 id | id 唯一 | |
getName() | 获取线程名 | ||
setName(String) | 修改线程名 | ||
getPriority() | 获取线程优先级 | ||
setPriority(int) | 修改线程优先级 | java中规定线程优先级是1~10 的整数,较大的优先级能提高该线程被 CPU 调度的机率 | |
getState() | 获取线程状态 | Java 中线程状态是用 6 个 enum 表示,分别为:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED | |
isInterrupted() | 判断是否被打断, | 不会清除 打断标记 |
|
isAlive() | 线程是否存活(还没有运行完毕) | ||
interrupt() | 打断线程 | 如果被打断线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除打断标记 ;如果打断的正在运行的线程,则会设置 打断标记 ;park 的线程被打断,也会设置打断标记 |
|
interrupted() | static | 判断当前线程是否被打断 | 会清除 打断标记 |
currentThread() | static | 获取当前正在执行的线程 | |
sleep(long n) | static | 让当前执行的线程休眠n毫秒,休眠时让出 cpu 的时间片给其它线程 | |
yield() | static | 提示线程调度器让出当前线程对CPU的使用 | 主要是为了测试和调试 |
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
/**
* @description:
* @author: teago
* @time: 2020/5/16 10:22
*/
@Slf4j
public class Example5 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
log.info(Thread.currentThread().getName() + ">>>>>> t1 execute");
});
// log.info(thread.getState().name());
thread.run();
// log.info(thread.getState().name());
// thread.start();
// log.info(thread.getState().name());
}
}
运行结果
10:57:48 [main] com.bloom.concurrent.three.Example5 - main>>>>>> t1 execute
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
/**
* @description:
* @author: teago
* @time: 2020/5/16 10:22
*/
@Slf4j
public class Example5 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
log.info(Thread.currentThread().getName() + ">>>>>> t1 execute");
});
// log.info(thread.getState().name());
// thread.run();
// log.info(thread.getState().name());
thread.start();
// log.info(thread.getState().name());
}
}
运行结果:
10:58:53 [Thread-0] com.bloom.concurrent.three.Example5 - Thread-0>>>>>> t1 execute
小结
修改以上代码:
log.info(thread.getState().name());
thread.run();
log.info(thread.getState().name());
thread.start();
log.info(thread.getState().name());
运行结果:(也说明了上述的问题)
1:00:04 [main] com.bloom.concurrent.three.Example5 - NEW
11:00:04 [main] com.bloom.concurrent.three.Example5 - main>>>>>> t1 execute
11:00:04 [main] com.bloom.concurrent.three.Example5 - NEW
11:00:04 [main] com.bloom.concurrent.three.Example5 - RUNNABLE
11:00:04 [Thread-0] com.bloom.concurrent.three.Example5 - Thread-0>>>>>> t1 execute
package com.beatshadow.concurrent.chapter3;
import java.util.concurrent.TimeUnit;
/**
*
* @author : <a href="mailto:gnehcgnaw@gmail.com">gnehcgnaw</a>
* @since : 2020/4/27 22:12
*/
public class Example6 {
public static void main(String[] args) {
new Thread("td1"){
@Override
public void run() {
try {
System.out.println(this.getState());
TimeUnit.MINUTES.sleep(1);
System.out.println(this.getState());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
package com.bloom.concurrent.three;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
/**
* @description:
* @author: teago
* @time: 2020/5/16 10:47
*/
@Slf4j
public class Example7 {
@SneakyThrows
public static void main(String[] args) {
Thread thread = new Thread("td2"){
@Override
public void run() {
try {
log.info("thread execute");
Thread.sleep(2000);
log.info("thread execute end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
log.info("main thread execute start");
Thread.sleep(1000);
log.info("main thread execute end");
// thread_execute.interrupt();
}
}
运行结果如下所示:(程序没有出错,线程在休眠之后继续执行)
11:12:31 [main] com.bloom.concurrent.three.Example7 - main thread execute start
11:12:31 [td2] com.bloom.concurrent.three.Example7 - thread execute
11:12:32 [main] com.bloom.concurrent.three.Example7 - main thread execute end
11:12:33 [td2] com.bloom.concurrent.three.Example7 - thread execute end
修改程序,添加interrupt()的调用:
thread.interrupt();
运行结果如下所示:
11:13:23 [main] com.bloom.concurrent.three.Example7 - main thread execute start
11:13:23 [td2] com.bloom.concurrent.three.Example7 - thread execute
11:13:24 [main] com.bloom.concurrent.three.Example7 - main thread execute end
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.bloom.concurrent.three.Example7$1.run(Example7.java:21)
总结:线程被打断,sleep之后的未被执行,因为程序出现异常。
让出,谦让的意思。
sleep让线程从running变成waiting状态,yield让线程从running变成runnable状态;
runnable状态的线程有可能被执行,而waiting状态的线程只有能到线程休眠之后才又可能被执行。
示例代码:
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
/**
* @description:
* @author: teago
* @time: 2020/5/16 11:23
*/
@Slf4j
public class Example8 {
public static void main(String[] args) {
new Thread(() -> {
while (true){
//业务代码
}
}).start();
}
}
让线程睡眠一段时间。
package com.bloom.concurrent.three;
/**
* @description:
* @author: teago
* @time: 2020/5/16 11:26
*/
public class Example9 {
public static void main(String[] args) {
new Thread(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
在没有利用CPU计算时,不要让while(true)空转去浪费cpu,这时可以使用sleep或者yield来让出cpu的使用权给其他程序。
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
import static java.lang.Thread.sleep;
/**
* @description:
* @author: teago
* @time: 2020/5/16 11:28
*/
@Slf4j
public class Example10 {
static int r = 0;
public static void main(String[] args) {
test1();
}
private static void test1() {
log.debug("开始");
Thread t1 = new Thread(() -> {
log.debug("开始");
try {
sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("结束");
r = 10;
});
t1.start();
log.debug("结果为:{}", r);
log.debug("结束");
}
}
上面的代码执行,打印 r 是什么?
r=10
r=0
解决方法
以调用方角度来讲,如果
问,下面代码 cost 大约多少秒?
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
import static java.lang.Thread.sleep;
/**
* @description:
* @author: teago
* @time: 2020/5/16 16:36
*/
@Slf4j
public class Example11 {
static int r1 = 0;
static int r2 = 0;
public static void main(String[] args) throws InterruptedException {
test2();
}
private static void test2() throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
r1 = 10;
});
Thread t2 = new Thread(() -> {
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
r2 = 20;
});
long start = System.currentTimeMillis();
t1.start();
t2.start();
t1.join();
t2.join();
long end = System.currentTimeMillis();
log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
}
}
分析如下
如果颠倒两个 join 呢?
最终都是输出
16:38:53 [main] com.bloom.concurrent.three.Example11 - r1: 10 r2: 20 cost: 2003
等够时间
static int r1 = 0;
static int r2 = 0;
public static void main(String[] args) throws InterruptedException {
test3();
}
public static void test3() throws InterruptedException {
Thread t1 = new Thread(() -> {
sleep(1);
r1 = 10;
});
long start = System.currentTimeMillis();
t1.start();
// 线程执行结束会导致 join 结束
t1.join(1500);
long end = System.currentTimeMillis();
log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
}
输出
20:48:01.320 [main] c.TestJoin - r1: 10 r2: 0 cost: 1010
没等够时间
static int r1 = 0;
static int r2 = 0;
public static void main(String[] args) throws InterruptedException {
test3();
}
public static void test3() throws InterruptedException {
Thread t1 = new Thread(() -> {
sleep(2);
r1 = 10;
});
long start = System.currentTimeMillis();
t1.start();
// 线程执行结束会导致 join 结束
t1.join(1500);
long end = System.currentTimeMillis();
log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
}
输出
20:52:15.623 [main] c.TestJoin - r1: 0 r2: 0 cost: 1502
这几个方法都会让线程进入阻塞状态
打断 sleep 的线程, 会清空打断状态(即:Thread.isInterrupt()= false),以 sleep 为例
package com.bloom.concurrent.three;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
/**
* @description:
* @author: teago
* @time: 2020/5/16 16:44
*/
@Slf4j
public class Example12 {
@SneakyThrows
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1");
log.info("t1 start");
t1.start();
TimeUnit.SECONDS.sleep(1);
t1.interrupt();
log.info("t1 interrupt");
log.info(t1.isInterrupted() + "");
}
}
运行结果:
16:48:55 [main] com.bloom.concurrent.three.Example12 - t1 start
16:48:56 [main] com.bloom.concurrent.three.Example12 - t1 interrupt
16:48:56 [main] com.bloom.concurrent.three.Example12 - false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at com.bloom.concurrent.three.Example12.lambda$main$0(Example12.java:20)
at java.lang.Thread.run(Thread.java:748)
Process finished with exit code 0
package com.beatshadow.concurrent.chapter3;
import lombok.extern.slf4j.Slf4j;
/**
* @author : <a href="mailto:gnehcgnaw@gmail.com">gnehcgnaw</a>
* @since : 2020/4/28 11:58
*/
@Slf4j
public class Example13 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true){
}
});
log.debug("thread start");
thread.start();
log.debug("thread interrupt");
thread.interrupt();
}
}
运行结果:
正常运行的线程如果被打断,线程并不会直接结束运行,只是说将interrupt的状态置为了true,这时候需要我们认为的代码进行干涉从而结束线程。
修改程序,使其优雅打断执行的线程:
package com.beatshadow.concurrent.chapter3;
import lombok.extern.slf4j.Slf4j;
/**
* @author : <a href="mailto:gnehcgnaw@gmail.com">gnehcgnaw</a>
* @since : 2020/4/28 11:58
*/
@Slf4j
public class Example13 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true){
//认为打断线程
if (Thread.currentThread().isInterrupted()) {
log.debug("线程被打断");
break;
}
}
});
log.debug("thread start");
thread.start();
log.debug("thread interrupt");
//这时候用户线程并未结束,只是说被打断的线程的interrupt=true ,这时候需要我们根据这个状态进行人工干涉
thread.interrupt();
}
}
Two Phase Termination
在一个线程T1只如何“优雅”终止线程T2?这里的【优雅】指的是给T2一个料理后事的机会。
Java多线程编程实战指南
——两阶段终止模式
演示代码:
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
/**
* @description:
* @author: teago
* @time: 2020/5/16 17:09
*/
public class Example15 {
public static void main(String[] args) {
TwoPhaseTermination twoPhaseTermination = new TwoPhaseTermination();
twoPhaseTermination.start("demo");
try {
Thread.sleep(3500);
} catch (InterruptedException e) {
e.printStackTrace();
}
twoPhaseTermination.stop();
}
}
@Slf4j
class TwoPhaseTermination {
private Thread thread;
public void start(String threadName) {
log.info(threadName + "线程启动");
thread = new Thread(() -> {
while (true) {
if (thread.isInterrupted()) {
log.info("料理后事");
break;
} else {
try {
TimeUnit.SECONDS.sleep(2); // 打断1
log.info("执行监控记录");
} catch (InterruptedException e) {
e.printStackTrace();
// 重新设置打断标记
thread.interrupt();
}
}
}
}, threadName);
thread.start();
}
public void stop() {
if (null != thread) {
thread.interrupt();
}
}
}
运行结果:
17:16:17 [main] com.bloom.concurrent.three.TwoPhaseTermination - demo线程启动
17:16:19 [demo] com.bloom.concurrent.three.TwoPhaseTermination - 执行监控记录
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at com.bloom.concurrent.three.TwoPhaseTermination.lambda$start$0(Example15.java:40)
at java.lang.Thread.run(Thread.java:748)
17:16:21 [demo] com.bloom.concurrent.three.TwoPhaseTermination - 料理后事
park:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/LockSupport.html#park--
Thread thread = new Thread(() -> {
log.debug("thread execute");
LockSupport.park();
log.debug("unpark");
log.debug("continue to execute");
});
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// thread.interrupt();
}
运行结果:
使用了park()方法,以下的程序不会执行。
使用Thread.interrupt()可以打断park的中断
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.LockSupport;
/**
* @description:
* @author: teago
* @time: 2020/5/16 17:23
*/
@Slf4j
public class Example16 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
log.debug("thread execute");
LockSupport.park();
log.debug("unPark");
log.debug("continue to execute");
});
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
运行结果:
但是被中断的线程如果interrupt = true,后续要执行park,则不会被停止中断
演示代码:
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.LockSupport;
/**
* @description:
* @author: teago
* @time: 2020/5/16 17:23
*/
@Slf4j
public class Example16 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
log.debug("thread execute");
LockSupport.park();
log.debug("unPark");
log.debug("continue to execute");
LockSupport.park();
log.debug("seconds continue to execute ");
});
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
运行结果:(发现第二次调用park(),并没有被终止后续代码的执行)
这时候需要使用Thread.interrupted()清除打断标记,具体如下所示:
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.LockSupport;
/**
* @description:
* @author: teago
* @time: 2020/5/16 17:23
*/
@Slf4j
public class Example16 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
log.debug("thread execute");
LockSupport.park();
//清除打断标记
Thread.interrupted();
log.debug("unPark");
log.debug("continue to execute");
LockSupport.park();
log.debug("seconds continue to execute ");
});
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
还有一些不推荐使用的方法,这些方法已过时,容易破坏同步代码块,造成线程死锁
方法名 | static | 功能说明 |
---|---|---|
stop() | 停止线程运行 | |
suspend() | 挂起(暂停)线程运行 | |
resume() | 恢复线程运行 |
默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。
package com.beatshadow.concurrent.chapter3;
import lombok.extern.slf4j.Slf4j;
/**
* @author : <a href="mailto:gnehcgnaw@gmail.com">gnehcgnaw</a>
* @since : 2020/4/28 14:45
*/
@Slf4j
public class Example16 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true){
}
});
thread.start();
try {
Thread.sleep(1000);
log.debug("main execute finish");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
原因:(主线程执行完成,但是进程并未停止,原因是thread线程还在执行)
验证:在main线程执行完之后,在if处打断点,有如下情况:
说明:此时thread线程还在执行。
那如何结束这个线程呢?
设置为守护线程,有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。
使用thread.setDaemon(true);
package com.beatshadow.concurrent.chapter3;
import lombok.extern.slf4j.Slf4j;
/**
* @author : <a href="mailto:gnehcgnaw@gmail.com">gnehcgnaw</a>
* @since : 2020/4/28 14:45
*/
@Slf4j
public class Example16 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true){
if (Thread.currentThread().isInterrupted()){
break;
}
}
});
//设置当前线程为守护线程,默认为false
thread.setDaemon(true);
thread.start();
try {
Thread.sleep(1000);
log.debug("main execute finish");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
**注意 **
- 垃圾回收器线程就是一种守护线程(当线程结束之后,就不需要进行垃圾回收了)
- Tomcat 中的 Acceptor 和 Poller 线程都是守护线程,所以 Tomcat 接收到 shutdown 命令后,不会等待它们处理完当前请求
这是从 操作系统 层面来描述的
这是从 Java API 层面来描述的
根据 Thread.State 枚举,分为六种状态
NEW
?线程刚被创建,但是还没有调用 start()
方法RUNNABLE
当调用了 start()
方法之后,注意,Java API 层面的 RUNNABLE
状态涵盖了 操作系统 层面的【可运行状态】、【运行状态】和【阻塞状态】(由于 BIO 导致的线程阻塞,在 Java 里无法区分,仍然认为是可运行)BLOCKED
,WAITING
,TIMED_WAITING
都是 Java API 层面对【阻塞状态】的细分,后面会在状态转换一节详述TERMINATED
当线程代码运行结束package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
/**
* @author : <a href="mailto:gnehcgnaw@gmail.com">gnehcgnaw</a>
* @since : 2020/4/28 15:21
*/
@Slf4j
public class TestState {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
}, "t1");
Thread thread2 = new Thread(() -> {
while (true) {
}
}, "t2");
thread2.start();
Thread thread3 = new Thread(() -> {
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t3");
thread3.start();
Thread thread4 = new Thread(() -> {
synchronized (TestState.class) {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t4");
thread4.start();
Thread thread5 = new Thread(() -> {
synchronized (TestState.class) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t5");
thread5.start();
Thread thread6 = new Thread(() -> {
}, "t6");
thread6.start();
log.debug(String.valueOf(thread1.getState()));
log.debug(String.valueOf(thread2.getState()));
log.debug(String.valueOf(thread3.getState()));
log.debug(String.valueOf(thread4.getState()));
log.debug(String.valueOf(thread5.getState()));
log.debug(String.valueOf(thread6.getState()));
}
}
运行结果:
阅读华罗庚《统筹方法》,给出烧水泡茶的多线程解决方案,提示
附:华罗庚《统筹方法》
统筹方法,是一种安排工作进程的数学方法。它的实用范围极广泛,在企业管理和基本建设中,以及关系复杂的科研项目的组织与管理中,都可以应用。
怎样应用呢?主要是把工序安排好。
比如,想泡壶茶喝。当时的情况是:开水没有;水壶要洗,茶壶、茶杯要洗;火已生了,茶叶也有了。怎么办?
- 办法甲:洗好水壶,灌上凉水,放在火上;在等待水开的时间里,洗茶壶、洗茶杯、拿茶叶;等水开了,泡茶喝。
- 办法乙:先做好一些准备工作,洗水壶,洗茶壶茶杯,拿茶叶;一切就绪,灌水烧水;坐待水开了,泡茶喝。
- 办法丙:洗净水壶,灌上凉水,放在火上,坐待水开;水开了之后,急急忙忙找茶叶,洗茶壶茶杯,泡茶喝。
哪一种办法省时间?我们能一眼看出,第一种办法好,后两种办法都窝了工。
这是小事,但这是引子,可以引出生产管理等方面有用的方法来。
水壶不洗,不能烧开水,因而洗水壶是烧开水的前提。没开水、没茶叶、不洗茶壶茶杯,就不能泡茶,因而这些又是泡茶的前提。它们的相互关系,可以用下边的箭头图来表示:
> 从这个图上可以一眼看出,办法甲总共要16分钟(而办法乙、丙需要20分钟)。如果要缩短工时、提高工作效率,应当主要抓烧开水这个环节,而不是抓拿茶叶等环节。同时,洗茶壶茶杯、拿茶叶总共不过4分钟,大可利用“等水开”的时间来做。
是的,这好像是废话,卑之无甚高论。有如走路要用两条腿走,吃饭要一口一口吃,这些道理谁都懂得。但稍有变化,临事而迷的情况,常常是存在的。在近代工业的错综复杂的工艺过程中,往往就不是像泡茶喝这么简单了。任务多了,几百几千,甚至有好几万个任务。关系多了,错综复杂,千头万绪,往往出现“万事俱备,只欠东风”的情况。由于一两个零件没完成,耽误了一台复杂机器的出厂时间。或往往因为抓的不是关键,连夜三班,急急忙忙,完成这一环节之后,还得等待旁的环节才能装配。
洗茶壶,洗茶杯,拿茶叶,或先或后,关系不大,而且同是一个人的活儿,因而可以合并成为:
看来这是“小题大做”,但在工作环节太多的时候,这样做就非常必要了。
这里讲的主要是时间方面的事,但在具体生产实践中,还有其他方面的许多事。这种方法虽然不一定能直接解决所有问题,但是,我们利用这种方法来考虑问题,也是不无裨益的。
package com.bloom.concurrent.three;
import lombok.extern.slf4j.Slf4j;
/**
* @description:
* @author: teago
* @time: 2020/5/16 18:44
*/
@Slf4j
public class Example18 {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
try {
log.debug("洗水壶");
Thread.sleep(5000);
log.debug("烧开水");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "老王");
Thread thread2 = new Thread(() -> {
try {
log.debug("洗茶壶");
Thread.sleep(1000);
log.debug("拿茶叶");
thread1.join();
log.debug("泡茶");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "小王");
thread1.start();
thread2.start();
}
}
运行结果:
18:45:26 [老王] com.bloom.concurrent.three.Example18 - 洗水壶
18:45:26 [小王] com.bloom.concurrent.three.Example18 - 洗茶壶
18:45:27 [小王] com.bloom.concurrent.three.Example18 - 拿茶叶
18:45:31 [老王] com.bloom.concurrent.three.Example18 - 烧开水
18:45:31 [小王] com.bloom.concurrent.three.Example18 - 泡茶
缺陷:(后续改进)
本章的重点在于掌握
原文:https://www.cnblogs.com/teago/p/12901718.html