本系列是写在代码里的记录,用来记录juc的学习过程
具体代码在github里嗷~
/*
线程常用方法
@author trotro
*/
@Slf4j(topic = "n2")
public class n2 {
/*
创建线程
列举主要三种模式
*/
@Test
public void creatThread() {
// 第一种创建线程方法
// 直接使用Thread类,写一个匿名内部类,同时重写run方法
Thread thread = new Thread("innerClass") {
//重写run
@Override
public void run() {
log.debug("running");
}
};
thread.start();
// 第二种使用Runnable配合Thread
// 实现Runnable方法
Runnable running2 = new Runnable() {
@Override
public void run() {
log.debug("running2");
}
};
Thread thread1 = new Thread(running2, "Runnable");
thread1.start();
// 第二点五种使用Lambda配合Thread
// 比较常用嗷
Thread thread2 = new Thread(() -> log.debug("running3"), "lambda");
thread2.start();
// 第三种使用FutureTask配合Thread
// FutureTask能够接受返回值
FutureTask<Integer> task = new FutureTask<>(() -> {
log.debug("task");
return 100;
});
Thread thread3 = new Thread(task, "Future");
thread3.start();
try {
log.debug("出现结果:{}", task.get());
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
log.debug("main");
}
/*
观察线程
看到线程交替运行
1.使用window(tasklist)或linux(ps)(top -H -p pid查看这个pid的所有进程实时)提供的查看方式
2.jps 查看所有java的进程,和pid
3.jstack pid 查看该pid的所有进程
4.jconsole pid 图形化查看pid
*/
@Test
public void watch() throws InterruptedException {
new Thread(() -> {
while (true) {
log.debug("running");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "t1").start();
new Thread(() -> {
while (true) {
log.debug("2Running");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "t2").start();
TimeUnit.SECONDS.sleep(2);
}
/*
使用Debug 观察栈帧,可以看到线程是在操作中可以随时创建的
上下文切换:
触发线程的被动方法,例如时间片用完(任务调度器在时钟提醒后,会进行任务调度切换线程)、
垃圾回收(在垃圾回收的时候,会切换线程到垃圾回收的线程)、有更高的优先级线程调用
触发上下文切换的主动方法,
线程内部使用{Thread.sleep()}将对cpu的使用放弃xx秒
{Thread.yield}主动放弃对cpu的使用,优先让其他线程使用
{thread.wait()}(不建议直接使用wait)让当前线程等待直到它被唤醒,通常是通过通知或中断
{thread.join()}同上
{park synchronized lock}同样也会触发上下文切换
*/
@Test
public void frames() {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
log.debug("hihi");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
thread.start();
new Thread(() -> {
try {
Thread.sleep(1000);
log.debug("hihi");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
log.debug(String.valueOf(System.nanoTime()));
}
/*
常用方法:
start与run
*/
@Test
public void methods() {
// 运行可以看到线程名字为main,所以run只是单纯调用关系
Thread thread = new Thread(() -> {
log.debug(Thread.currentThread().getName());
});
thread.start();
thread.run();
log.debug("start");
log.debug(">>>>>>>>");
// 打断
Thread thread1 = new Thread(() -> {
synchronized (Thread.class) {
log.debug("sleep");
try {
TimeUnit.SECONDS.sleep(1);
TimeUnit.MILLISECONDS.sleep(2);
} catch (InterruptedException e) {
log.debug("wake up!");
throw new RuntimeException(e);
}
}
});
thread1.start();
try {
Thread.sleep(1000);
thread1.interrupt();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/*
优先级和yield
*/
@Test
public void yieldP() throws ExecutionException, InterruptedException {
// 定义方法变量
AtomicInteger res0 = new AtomicInteger();
AtomicInteger res1 = new AtomicInteger();
Thread thread = new Thread(() -> {
while (true) {
if (Thread.currentThread().isInterrupted()) {
break;
}
res0.getAndIncrement(); // +1
}
});
Thread thread1 = new Thread(() -> {
while (true) {
if (Thread.currentThread().isInterrupted()) {
break;
}
try {
// Thread.yield();
} catch (Exception e) {
throw new RuntimeException(e);
}
res1.getAndIncrement(); // +1
}
});
// thread.setPriority(Thread.MAX_PRIORITY);
// thread1.setPriority(Thread.MIN_PRIORITY);
// 启动线程
thread.start();
thread1.start();
TimeUnit.SECONDS.sleep(2);
thread.interrupt();
thread1.interrupt();
// 查看结果
log.debug("thread0:{}", res0.get());
log.debug("thread1:{}", res1.get());
/*
可以看到,yield()对线程的影响还是十分大的。
向调度程序提示当前线程愿意放弃其当前对处理器的使用。调度程序可以随意忽略此提示。
Yield 是一种启发式尝试,旨在改善线程之间的相对进度,否则会过度使用 CPU。它的使用应与详细的分析和基准测试相结合,以确保它确实具有预期的效果。
使用这种方法很少是合适的。它可能对调试或测试有用,因为它可能有助于重现由于竞争条件导致的错误。在设计并发控制结构(如java.util.concurrent.locks包中的结构)时,它也可能很有用。
*/
}
/*
join的使用场景
*/
@Test
public void testJoin() {
Thread thread = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(2);
log.debug("yeyeyeyey");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
thread.start();
log.debug("不使用join");
log.debug("线程状态:{}", thread.getState());
log.debug(">>>>>>>");
try {
thread.join();
log.debug("线程状态:{}", thread.getState());
log.debug("使用join");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/*
打断标记
*/
@Test
public void interruptFlag(){
// 1.在正常情况下(非sleep,wait,join阻塞状态时候)进行打断,会标记上打断标记
// 注意,这种情况下不会停止线程运行
Thread thread = new Thread(() -> {
while (true) {
// 可以用来手动停止线程运行
// if (Thread.currentThread().isInterrupted()) {
// break;
// }
}
});
// 开始
log.debug("start");
thread.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//两秒后打断
log.debug("interrupt");
thread.interrupt();
//查看状态
log.debug("打断标记:{}", thread.isInterrupted());
log.debug("线程状态:{}", thread.getState()); //仍然运行
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.debug(">>>>>>>>>>>>.");
// 2.在sleep,或者wait、join的时候打断,会是false,因为trycatch直接捕获了异常
Thread interruptSleep = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
log.warn(e.toString());
}
});
// 开始
interruptSleep.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//一秒后打断
interruptSleep.interrupt();
log.debug("打断标记为:{}", interruptSleep.isInterrupted());
log.debug("线程状态:{}", interruptSleep.getState()); //TERMINATED 终止
}
/*
打断标记interrupted和park
*/
@Test
public void interruptAndPark() throws InterruptedException {
Thread thread = new Thread(() -> {
// park是locks的方法,用来让线程处阻塞状态
log.debug("park");
LockSupport.park();
log.debug("unpark,打断标记为:{}", Thread.currentThread().isInterrupted());
LockSupport.park();
log.debug("由于打断标记为true,park无用");
});
thread.start();
// 1秒后打断
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
thread.join();
// >>>>>>
Thread thread1 = new Thread(() -> {
log.debug("park");
LockSupport.park();
log.debug("unpark, 打断标记为:{},顺便清楚打断标记", Thread.interrupted());
LockSupport.park();
log.debug("unpark,看不见嗷");
});
thread1.start();
// 1秒后打断
TimeUnit.SECONDS.sleep(1);
thread1.interrupt();
thread1.join();
}
@Test
public void testThread() throws InterruptedException {
Thread thread = new Thread(() -> {
while(true) {
if (Thread.currentThread().isInterrupted()) {
break;
}
}
log.debug("结束了");
}, "t1");
thread.start();
TimeUnit.SECONDS.sleep(2);
log.debug("我go啦");
}
}