多线程基础(四)

一、等待线程-join()

在我们平常写代码的 时候会遇到需要等待一个线程执行完毕的时候,再执行下一个线程,然而我们之前学过的sleep具有以下特性:

  • 当前线程停止运行指定的毫秒数。时间一到,线程自动进入"就绪状态",等待 CPU 调度。
  • 它不释放锁。如果当前线程持有了某个对象的同步锁(synchronized),在 sleep 期间,其他线程依然无法获取该锁。

所以我们不可能精准预测每一个线程执行所耗费的时间,为了避免这个问题,我们通常用join()函数。

复制代码
public class demo3 {
    public static void main(String[] args) throws InterruptedException {
        Runnable target=()->{
            for (int i = 0; i < 10; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + " 我正在工作" );
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }
            System.out.println(Thread.currentThread().getName() + " 工作结束");
        };
        Thread t1=new Thread(target,"张三");
        Thread t2=new Thread(target,"李四");
        System.out.println("先让李四开始工作");
     t2.start();
        t2.join();
        System.out.println("李四工作结束了,让张三开始工作");
        t1.start();
        t1.join();

    }


}

join函数的特性:

复制代码
Thread t = new Thread(() -> { /* 任务 */ });
t.start();
t.join(); // 当前线程在这里卡住,直到 t 运行结束

当前线程阻塞,直到目标线程 t 执行完毕(终止)。

它底层其实也是利用了 wait() 机制,因此会释放锁。如果在 synchronized 块中调用 join(),当前线程会释放锁,允许其他线程进入临界区,直到目标线程结束或被中断。

常用于:主线程需要等待子线程计算结果后才能继续(例如:先下载数据,再处理数据)。

复制代码
join在main中就是主线程等待引用join的线程运行结束,
如果是在t2中使用t1.join就是t2等待t1结束

上面使用的join都是没有参数的版本,没有参数就是,等待的线程不结束就会一直等,这个等待会很容易出bug就像租界女友的男主(忘了叫什么了),一直舔着水原千鹤,但她是租界女友而且也不会喜欢他,这时候bug就出现了,男主就算等到老死也等不到水原千鹤喜欢他(看一部劝退)

这个时候我们就该引入带参数的join了

复制代码
public class demo4 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1=new Thread(()->{
            System.out.println("Hello from thread");
        });
        Thread thread2=new Thread(()->{
            System.out.println("Hello from thread");
            try {
                thread1.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        thread1.start();
        thread1.join();
        thread2.start();

    }
}

public class demo4 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1=new Thread(()->{
            System.out.println("Hello from thread");
        });
        Thread thread2=new Thread(()->{
            System.out.println("Hello from thread");
            try {
                thread1.join(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        thread1.start();
        thread1.join(1000);
        thread2.start();

    }
}

第三个没怎么用过,我这边就不提了。

复制代码
public static Thread currentThread();

咱们之前提到过这个方法,用来获取当前线程的引用

复制代码
public class demo5 {
    public static void main(String[] args) {
        Thread t=Thread.currentThread();
        System.out.println(t.getName());
    }
}

再提一嘴sleep()方法:

sleep会让调用的线程阻塞等待,是有一定的时间的

线程执行sleep的时候就会使这个线程不参与cpu的调度,从而把cpu的资源让出来,给别人用。

这种操作被称为"放权",再某些开发的过程中发现cpu占用过高就可以通过sleep来进行改善。

线程状态

线程共有六种状态

  • new
  • runnable
  • blocked
  • waiting
  • timed_waiting
  • terminated

进程状态:

  • 就绪
  • 阻塞

就绪:正在cpu上执行或者随时可以去cpu上执行

阻塞:暂时不参与cpu执行

线程内的状态是一个枚举类型Thread.State

复制代码
public class demo6 {
    public static void main(String[] args) {
        for (Thread.State state:Thread.State.values()){
            System.out.println(state);
        }
    }
}

运行结果为:

复制代码
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED

new:当前Thread对象虽然有了,但是内核的线程还没有(这个时候并没有调用start)

runnable:就绪态,正在cpu上执行或者随时可以去cpu上执行

以下三个是阻塞态:

  • blocked,因为锁竞争而近期的阻塞
  • waiting,没有超时等待
  • timed_waiting,有超时等待或者join带参数版本
相关推荐
霸道流氓气质2 分钟前
Spring AI 技术细节:RAG QuestionAnswerAdvisor 设计与实现
java·人工智能·spring
平头哥AI25 分钟前
Day 01 | go run 跑通第一个 Go 程序,go build 留下一个能拷走的 exe
开发语言·后端·golang
斑马13931 分钟前
Linux软件编程学习笔记(十二)——TCP并发服务器模型
java·服务器·网络
冬栈程序设计35 分钟前
Springboot宿舍管理系统【670099】 -附源码(开箱即用)
java·毕业设计·springboot·课程设计·程序设计·大作业
2601_9622845044 分钟前
北京Java全栈开发培训 Web前端开发 软件测试就业培训班
java·软件测试·web前端·全栈开发·就业培训
葡萄城技术团队1 小时前
工业数据可视化:使用活字格 AIcoding + Three.js 构建轻量化三维设备监控大屏
开发语言·javascript·信息可视化
qiaosaifei1 小时前
JAVA老项目中有大量的类名_编译时报找不到符号错误
java·开发语言
聪明蛋子哟1 小时前
MCP协议深度落地:如何用Python/Java双语言实现统一的工具调用网关?
java·开发语言·python
文子越来越强1 小时前
【双因子认证】拦截注解@MFACheck 接入指南(其他微服务如何用)
java
一晌小贪欢2 小时前
python-第27天:Python面向对象详解
开发语言·python·数据可视化·面向对象·python办公