目录
一、线程名称设置和获取
二、线程的sleep()
三、线程的interrupt
四、join()
五、yield()
六、wait(),notify(),notifyAll()
1、线程名称一般在线程启动前设置,但也允许为正在运行的线程设置名称。在实际开发中,在使用多线程开发时,一定要自定义线程名称,偏于查找日志。
2、线程允许使用同样的名字,但应该尽量避免。
3、如果线程没有命名,系统会自动为线程设置名称。例如Thread-0,Thread-1。在SpringBoot中http-nio-端口号-exec-1,http-nio-端口号-exec-2。
线程命名
package com.xiaojie.juc.thread.base;
/**
* @author xiaojie
* @version 1.0
* @description: 线程命名和获取名称
* @date 2021/12/17 22:54
*/
public class ThreadNameDemo {
public static void main(String[] args) {
A a = new A();
new Thread(a,"mythraed-a").start();
new Thread(a,"mythraed-b").start();
}
static class A implements Runnable{
@Override
public void run() {
//获取线程名称
System.out.println("当前线程的名称是>>>>>>>>:"+Thread.currentThread().getName());
}
}
}
线程池命名
package com.xiaojie.juc.thread.base;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author xiaojie
* @version 1.0
* @description: 线程池命名
* @date 2021/12/17 23:09
*/
public class ThreadPoolNameDemo {
private static final AtomicInteger threadNumber = new AtomicInteger(1);
private static final String MYTHREAD_POOL_GROUP = "mythread-pool-group-thread-";
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3,
r -> new Thread(new ThreadGroup(""), r,
MYTHREAD_POOL_GROUP + threadNumber.getAndIncrement(),
0));
for (int i = 0; i < 10; i++) {
executorService.execute(() ->
System.out.println("当前线程名称>>>>>>>>>:" + Thread.currentThread().getName()));
}
//关闭线程池
executorService.shutdown();
}
}
package com.xiaojie.juc.thread.base;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author xiaojie
* @version 1.0
* @description: 线程sleep方法
* @date 2021/12/17 23:46
*/
public class ThreadSleepDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
try {
if (Thread.currentThread().isInterrupted()) {
System.out.println("Thread is Interrupted");
}
//一定要捕捉InterruptedException异常
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName());
});
}
//关闭线程池
executorService.shutdown();
}
}
sleep的作用是让目前正在执行的线程休眠,让CPU去执行其他任务,使线程从运行状态进去阻塞状态。当线程睡眠时间满后,线程并不一定是立刻马上开始执行,因为CPU可能正在执行其他任务,线程进入就绪状态,等待CPU分配时间片后才能执行。
Thread提供了stop(),但是是个过时方法,不推荐使用。stop()方法是强制中断线程,不管当前线程是否正在运行,有可能导致当前线程持有当前锁,强行中断后可能不会释放锁。interrupt()并不是用来中断一个线程,而是将线程设置为中断状态。
1、如果执行interrupt()时,当前线程处于阻塞状态(wait(),sleep(),join())时,线程会立刻退出阻塞,抛出InterruptedException异常。
2、如果调用interrupt()时,线程处于运行状态,线程不受任何影响,只是会将中断标识设置为true,可以调用isInterrupted(),判断是否中断。
package com.xiaojie.juc.thread.base;
/**
* @author xiaojie
* @version 1.0
* @description: 线程中断
* @date 2021/12/18 0:12
*/
public class InterruptDemo {
public static void main(String[] args) {
A a = new A();
a.start();
}
static class A extends Thread {
@Override
public void run() {
//手动中断线程
Thread.currentThread().interrupt();
try {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("线程中断了");
break;
}
}
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("线程中断了。。。。。when sleep");
}
}
}
}
线程A在运行时,线程Bjoin(),之后,线程A会等待直到线程B运行完之后,才开始执行。如果线程B无限制运行,线程A可以设置等待时长join(1000)单位是毫秒。
package com.xiaojie.juc.thread.base;
/**
* @author xiaojie
* @version 1.0
* @description:线程join模拟
* @date 2021/12/18 0:45
*/
public class ThreadJoinDemo {
public static void main(String[] args) {
new A().start();
}
static class A extends Thread {
@Override
public void run() {
try {
B b = new B();
b.start();
b.join();//B线程join之后,A线程需要等待B运行完之后才执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A执行任务。。。。。。。");
}
}
static class B extends Thread {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程B执行任务。。。。。。。");
}
}
}
yield的作用是让正在执行的线程让出CPU的执行权限,使得CPU可以去执行其他任务。从线程状态来看,线程从运行变为就绪状态。线程在yield()方法之后,线程放弃和重占CPU是不确定的,可能是刚刚放弃CPU,马上又获得CPU执行权。yield不会阻塞线程,只会让当前线程暂停一下,让系统线程调度器重新调度一次。
package com.xiaojie.juc.thread.base;
/**
* @author xiaojie
* @version 1.0
* @description: Yield实例
* @date 2021/12/18 1:13
*/
public class ThreadYieldDemo {
public static void main(String[] args) {
Thread threadA = new Thread(new A());
threadA.setPriority(1);
threadA.setName("threadA ");
Thread threadB = new Thread(new B());
threadB.setName("threadB ");
threadA.start();
threadB.start();
}
static class A implements Runnable {
@Override
public void run() {
//暂停一下,重新调度线程
Thread.yield();
System.out.println(Thread.currentThread().getName());
}
}
static class B implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
}
这三个方法不是Thread独有的方法,是Object的方法!!!
当一个对象实例调用了wait()方法后,当前线程会在这个对象上等待。直到其他线程调用这个实例的notify(),或者notifyAll()方法后才会唤醒。调用了wait()方法后,该线程就会进入该实例的等待队列,如果队列中有多个线程,notify()只会随机的唤醒一个线程。这个选择是不公平的,不是先等待的就会先唤醒。notifyAll(),是唤醒所有的等待线程。而且这些方法只能在synchronized代码块中使用。wait()和sleep()都会让线程等待,但是wait()方法会释放目标对象的锁,而sleep()方法不会释放任何资源。
package com.xiaojie.juc.thread.base;
/**
* @author xiaojie
* @version 1.0
* @description: wait demo
* @date 2021/12/18 1:43
*/
public class ThreadWaitDemo {
private static final Object obj = new Object();
public static void main(String[] args) {
new Thread(new A()).start();
new Thread(new B()).start();
}
static class A implements Runnable {
@Override
public void run() {
synchronized (obj) {
System.out.println("线程A开始等待。。。。。。");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A等待结束。。。。。。");
System.out.println("线程A开始执行。。。。。。");
}
}
}
static class B implements Runnable {
@Override
public void run() {
synchronized (obj) {
try {
obj.notify();
Thread.sleep(2000);
System.out.println("线程B运行。。。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
参考:《JAVA高并发核心编程(卷2):多线程、锁、JMM、JUC、高并发设计》-尼恩编著