多线程基础体系知识清单(中)

简介: 多线程基础体系知识清单(中)

实现方式1(错误示例):


public class Main implements Callable<String>{
    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        String str = "我是带返回值的子线程";
        return str;
    }
    public static void main(String[] args) {
        Main main = new Main();
        try {
            String str = main.call();
            System.out.println(str);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


运行结果:


image.png


实现方式2(使用FutureTask):


public class Main implements Callable<String>{
    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        String str = "我是带返回值的子线程";
        return str;
    }
    public static void main(String[] args) {
        FutureTask<String> task = new FutureTask<String>(new Main());
        new Thread(task).start();
        try {
            if(!task.isDone()) {
                System.out.println("任务没有执行完成");
            }
            System.out.println("等待中...");
            Thread.sleep(3000);
            System.out.println(task.get());
        } catch (InterruptedException | ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


运行结果:


image.png


实现方法3(使用线程池配合Future获取):


public class Main implements Callable<String>{
    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        String str = "我是带返回值的子线程";
        return str;
    }
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService newCacheThreadPool = Executors.newCachedThreadPool(); 
        Future<String> future = newCacheThreadPool.submit(new Main());
        if(!future.isDone()) {
            System.out.println("线程尚未执行结束");
        }
        System.out.println("等待中");
        Thread.sleep(300);
        System.out.println(future.get());
        newCacheThreadPool.shutdown();
    }
}


运行结果:


image.png



线程的状态


Java线程主要分为以下六个状态:新建态(new),运行态(Runnable),无限期等待

(Waiting),限期等待(TimeWaiting),阻塞态(Blocked),结束(Terminated)


新建(new)


新建态是线程处于已被创建但没有被启动的状态,在该状态下的线程只是被创建出来了,但并没有开始执行其内部逻辑。


运行(Runnable)


运行态分为Ready和Running,当线程调用start方法后,并不会立即执行,而是去争夺CPU,当线程没有开始执行时,其状态就是Ready,而当线程获取CPU时间片后,从Ready态转为Running态。



等待(Waiting)


处于等待状态的线程不会自动苏醒,而只有等待被其它线程唤醒,在等待状态中该线程不会被CPU分配时间,将一直被阻塞。以下操作会造成线程的等待:


  1. 没有设置timeout参数的Object.wait()方法。
  2. 没有设置timeout参数的Thread.join()方法。
  3. LockSupport.park()方法(实际上park方法并不是LockSupport提供的,而是在Unsafe中,LockSupport只是对其做了一层封装,可以看我的另一篇博客《锁》,里面对于ReentrantLock的源码解析有提到这个方法)。


锁:https://juejin.im/post/5d8da403f265da5b5d203bf4


限期等待(TimeWaiting)


处于限期等待的线程,CPU同样不会分配时间片,但存在于限期等待的线程无需被其它线程显式唤醒,而是在等待时间结束后,系统自动唤醒。以下操作会造成线程限时等待:

  1. Thread.sleep()方法。

  2. 设置了timeout参数的Object.wait()方法。
  3. 设置了timeout参数的Thread.join()方法。
  4. LockSupport.parkNanos()方法。
  5. LockSupport.parkUntil()方法。


阻塞(Blocked)


当多个线程进入同一块共享区域时,例如Synchronized块、ReentrantLock控制的区域等,会去整夺锁,成功获取锁的线程继续往下执行,而没有获取锁的线程将进入阻塞状态,等待获取锁。


结束(Terminated)


已终止线程的线程状态,线程已结束执行。


Sleep和Wait的区别


Sleep和Wait者两个方法都可以使线程进入限期等待的状态,那么这两个方法有什么区别呢?


  1. sleep方法由Thread提供,而wait方法由Object提供。
  2. sleep方法可以在任何地方使用,而wait方法只能在synchronized块或synchronized方法中使用(因为必须获wait方法会释放锁,只有获取锁了才能释放锁)。
  3. sleep方法只会让出CPU,不会释放锁,而wait方法不仅会让出CPU,还会释放锁。


测试代码:


public class Main{
    public static void main(String[] args) {
        Thread threadA = new Thread(new ThreadA());
        Thread threadB = new Thread(new ThreadB());
        threadA.setName("threadA");
        threadB.setName("threadB");
        threadA.start();
        threadB.start();
    }
    public static synchronized void print() {
        System.out.println("当前线程:"+Thread.currentThread().getName()+"执行Sleep");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("当前线程:"+Thread.currentThread().getName()+"执行Wait");
        try {
            Main.class.wait(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("当前线程:"+Thread.currentThread().getName()+"执行完毕");
    }
}
class ThreadA implements Runnable{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        Main.print();
    }
}
class ThreadB implements Runnable{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        Main.print();
    }
}



执行结果:


image.png


从上面的结果可以分析出:当线程A执行sleep后,等待一秒被唤醒后继续持有锁,执行之后的代码,而执行wait之后,立即释放了锁,不仅让出了CPU还让出了锁,而后线程B立即持有锁开始执行,和线程A执行了同样的步骤,当线程B执行wait方法之后,释放锁,然后线程A拿到锁打印了第一个执行完毕,然后线程B打印执行完毕。



相关文章
|
8月前
|
监控 数据可视化 BI
清单管理软件推荐:提升任务效率与组织能力
**Zoho Projects是一款推荐的清单管理工具,它支持任务关联和实时更新显示,提升效率。通过派生和关联关系组织任务,用甘特图监控进度,还提供直观的统计报表功能。适合个人和中小企业免费试用,以优化工作流程。**
73 0
|
新零售 人工智能 供应链
链动2+1开发运营版丨链动2+1系统开发案例详情/方案项目/功能说明/逻辑规则/源码程序
新零售是指传统零售业与互联网技术相结合,通过数字化、数据化和智能化的手段,重新定义和升级传统零售业态的模式和经营方式。
|
9月前
|
前端开发 小程序 JavaScript
小程序生命周期详解,助你成为开发高手!
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。
|
Java 测试技术 BI
研发管理者如何7步规范管理企业代码资产?
本教程向您展示如何在云效上设置代码仓库模板,如何设置研发协作规范,如何启动代码检测,以及如何设置保护分支与合并卡点、如何实现研发工作与需求的自动化消息通知、如何度量代码数据?
41449 15
|
运维 测试技术 区块链
链动2+1模式系统开发指南流程丨成熟案例丨功能设计丨测试部署丨方案项目丨逻辑需求丨源码出售
链动2+1模式系统开发方案是指一个较为复杂的系统开发模式,其中包含两个公链和一个私链的组合。
DeFi流动性质押项目系统开发详细步骤/方案逻辑/案例开发/源码程序
DeFi (Decentralized Finance) pledge mining is a blockchain based financial activity that combines pledge and mining mechanisms. It provides a new way to provide benefits to participants and promote the development of a centralized financial ecosystem.
dapp丨defi代币合约质押项目系统开发逻辑详细/规则说明/案例设计/步骤细节/源码程序
The smart contract liquidity mining system is a financial application system based on smart contract technology, aimed at providing liquidity and receiving rewards by injecting users' funds into the liquidity pool and locking them in the smart contract.
|
Java 调度 数据库
【Java技术指南】「难点-核心-遗漏」Java线程状态流转及生命周期的技术指南(知识点串烧)!
【Java技术指南】「难点-核心-遗漏」Java线程状态流转及生命周期的技术指南(知识点串烧)!
176 0
【Java技术指南】「难点-核心-遗漏」Java线程状态流转及生命周期的技术指南(知识点串烧)!
|
监控 前端开发 数据库
微服务项目:尚融宝(45)(核心业务流程:借款申请(2))
微服务项目:尚融宝(45)(核心业务流程:借款申请(2))
微服务项目:尚融宝(45)(核心业务流程:借款申请(2))
|
前端开发 数据库 微服务
微服务项目:尚融宝(44)(核心业务流程:借款申请(1))
微服务项目:尚融宝(44)(核心业务流程:借款申请(1))
微服务项目:尚融宝(44)(核心业务流程:借款申请(1))

热门文章

最新文章