java并发(2)——线程的基本操作

java-多线程持续 Thread.yield():提出释放CPU时间⽚的请求。不会释放锁,线程依然处于RUNNABLE状态,即调度权让给别⼈,但⽴刻可以回到竞争线程锁的状态。 Thread.sleep():调⽤后线程处于阻塞状态,注:线程状态处于BLOCKED或WAITING或TIME_WAITING这三种统称为堵塞状态。 线程安全的常用数据结构 HashMap:ConcurrentHashMap ArrayList:CopyOnWriteArrayList Set:CopyOnWriteArraySet 关键字 vol 阅读详情

线程的基本操作

新建线程

java中建立线程可以有两种方式,分别是继承Thread类和实现Runnable接口。

public static class CreateThread extends Thread{
    @Override
    public void run() {
        System.out.println("Oh, I am CreateThread");
    }
}

public class CreateThread implements Runnable {
    @Override
    public void run() {
        System.out.println("Oh, I am Runnable");
    }
}

开启线程

开启线程的方式分为两种start(),run()

Thread t1 = new Thread();
t1.start()

Thread t2 = new Thread();
t2.run()

两者的区别为:

start()是开启一个新的线程并执行run()函数,run()只在当前线程之中串行执行run()的代码。

终止线程

通常情况线程执行完毕后就会结束,不需要手动关闭,例如绝大部分的worker类型的线程。但是有些服务端的后台线程会常驻系统(死循环方式)。

JDK中提供了Thread.stop()方法,不过是一个废弃的方法,原因是:stop()方法过于暴力,强行把执行到一半的线程终止,可能会引起一些数据不一致的问题。例如:Thread.stop()方法在结束线程的时候,会直接终止线程,并且会立即释放这个线程所持有的锁。而这些锁恰恰是用来维持对象一致性的。

更好的结束线程的方式是使用一个变量标识是否需要结束,或者使用中断的方式:

//每次都是执行完一个循环体之后再退出
//线程何时退出由程序员决定
public static class ChangeObjectThread extends Thread {
    volatile boolean stopme = false;

    public void stopMe(){
        stopme = true;
    }
    @Override
    public void run() {
        while (true) {
            if (stopme){
                System.out.println("exit by stop me");
                break;
            }
            //do something
        }
    }
}


//这里使用了中断判定来退出
public static class ChangeObjectThread extends Thread {

    @Override
    public void run() {
        while (true) {
            if (Thread.currentThread().isInterrupted()){
                System.out.println("exit with interrupted");
                break;
            }
            //do something
        }
    }
}

线程中断

与线程中断有关的,有三个方法:

public void Thread.interrupt()              //中断线程
public boolean Thread.isInterrupted()       //判断是否被中断
public static boolean Thread.interrupted()  //判断是否被中断,并清除中断标志,static
public static void main(String[] args) throws InterruptedException {
    Thread t1=new Thread(){
        @Override
        public void run(){
            while(true){
                // if(Thread.currentThread().isInterrupted()){
                //  System.out.println("Interruted!");
                //  break;
                // }
                Thread.yield();
            }
        }
    };
    t1.start();
    Thread.sleep(2000);
    t1.interrupt();
}

在这里虽然对t1进行了中断,但是在t1中并没有中断处理的逻辑(注释部分),因此即使t1线程被设置了中断状态,但是这个中断不会发生任何作用。

等待(wait)和通知(notify)

为了支持多线程之间的协作,JDK提供了两个非常重要的接口线程等待wait()方法和通知notify()\notifyAll()方法。这两个方法并不是在Thread类中的,而是输出Object类。

这也意味着任何对象都可以调用这两个方法。

public class SimpleWN {
    final static Object object = new Object();
    public static class T1 extends Thread{
        public void run()
        {
            synchronized (object) {
                System.out.println(System.currentTimeMillis()+":T1 start! ");
                try {
                    System.out.println(System.currentTimeMillis()+":T1 wait for object ");
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis()+":T1 end!");
            }
        }
    }
    public static class T2 extends Thread{
        public void run()
        {
            synchronized (object) {
                System.out.println(System.currentTimeMillis()+":T2 start! notify one thread");
                object.notify();
                System.out.println(System.currentTimeMillis()+":T2 end!");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                }
            }
        }
    }
    public static void main(String[] args) {
        Thread t1 = new T1() ;
        Thread t2 = new T2() ;
        t1.start();
        t2.start();
    }
}

上述的代码如果去除掉synchronized块,代码将无法运行。因为出现了java.lang.IllegalMonitorStateException。

首先,这儿要非常注意的几个事实是:

1)任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)

2)如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。

3)JVM基于多线程,默认情况下不能保证运行时线程的时序性

基于以上几点事实,我们需要确保让线程拥有对象的控制权。也就是说在T1中执行wait方法时,要保证T1对object有控制权;在T2中执行notify方法时,要保证T2对object有控制权。

挂起(suspend)和继续执行(resume)线程

suspend()和resume()是一对相反的操作,在JDK中已经是废弃的方法。不推荐suspend()去挂起线程的原因是因为suspend()在导致线程暂停的同时,并不会去释放任何资源。

更为严重的是如果resume()在suspend()之前就执行了,那么被挂起的线程可能很难有机会被继续执行。并且线程所持有的资源将不会被释放。

等待结束(join)和谦让(yield)

和字面意思一样。

线程组

public class ThreadGroupName implements Runnable {
    public static void main(String[] args) {
        //建立一个线程组
        ThreadGroup tg = new ThreadGroup("PrintGroup");
        //创建线程的时候将线程加入到线程组,使用了Thread的构造函数:
        //public Thread(ThreadGroup group, Runnable target, String name)
        Thread t1 = new Thread(tg, new ThreadGroupName(), "T1");
        Thread t2 = new Thread(tg, new ThreadGroupName(), "T2");
        t1.start();
        t2.start();
        //线程组中活动线程的总数,但是由于线程是动态的,所以这个只是一个估计值
        System.out.println(tg.activeCount());
        //列出线程组中的线程
        tg.list();
    }

    @Override
    public void run() {
        String groupAndName = Thread.currentThread().getThreadGroup().getName()
                + "-" + Thread.currentThread().getName();
        while (true) {
            System.out.println("I am " + groupAndName);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

![运行结果](https://img-blog.youkuaiyun.com/20171108164802243?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2ljb2ZpZWxk/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 运行结果 线程组还有一个应用就是ThreadGroup.stop()方法,不过其所存在的问题和Thread.stop()一样,因此使用时需要格外谨慎。

守护线程

守护线程是一种特殊的线程,它是系统的守护者,在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程。与之相对应的是用户线程,用户线程可以认为j是系统的工作线程。如果用户线程全部结束,这也意味这这个程序实际上无事可做了。守护线程要守护的对象已经不存在了,那么整个应用程序就自然应该结束。因此,当一个Java应用内,只有守护线程的时候,Java虚拟机就会自然退出。

简单看下守护线程的使用:

public class DaemonDemo {
    public static class DaemonT extends Thread{
        public void run(){
            while(true){
                System.out.println("I am alive");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t=new DaemonT();
        //必须在start()之前设置为守护线程
        t.setDaemon(true);
        t.start();

        Thread.sleep(2000);
    }
}

注意:守护线程Thread.setDaemon(true)必须要在线程start()之前设置,否则抛出java.lang.IllegalThreadStateException。设置无效,也不影响原来线程作为工作线程继续工作

线程优先级

在java中,使用1到10表示线程优先级(数字越大优先级越高)。一般可以使用Thread类中定义的三个静态标量来表示:


线程优先级
线程优先级


这里写图片描述
Thread.setPriority()例子

Java 线程池(Thread Pools)详解 线程池是一种重用线程的机制,用于提高线程的利用率和管理线程的生命周期,常用于多线程编程和异步编程。Java提供了多种线程池实现,其中最常用的是ThreadPoolExecutor类和Executors类提供的静态工厂方法。线程池由一个线程队列和一个任务队列组成,线程队列中保存着空闲线程,任务队列中保存着等待执行的任务。线程池启动后,线程池中的线程从任务队列中获取任务并执行,执行完毕后返回线程队列中等待下一次任务的到来。如果任务队列为空,线程池中的线程将等待新的任务到来或被关闭。 阅读详情

相关推荐

java 并发线程应用

ArrayBlockingQueue是一个有界缓存等待队列,可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的元素缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当ArrayBlockingQueue已满时,加入ArrayBlockingQueue失败,会开启新的线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的元素尝试加入ArrayBlockingQueue时会报错。IO密集型,即该任务需要大量的IO,即大量的阻塞。

qq_35216414的博客 1129

java 多个常驻实例_Java实现监控多个线程状态的简单实例

实例如下:import java.util.concurrent.CountDownLatch;import java.util.concurrent.Executor;import java.util.concurrent.Executors;/*** 测试监控类** @author**/public class WatchThread {/*** 测试函数** @throws Interrup...

weixin_36273006的博客 251

JAVA多线程、并发知识点总结

1、java多线程(一个优秀的博客)http://www.cnblogs.com/skywang12345/p/java_threads_category.html2、线程状态图http://www.cnblogs.com/skywang12345/p/3479024.html3、Callable、Future、FutureTaskhttp://blog.youkuaiyun.com/hbtj_1216/art

西瓜游侠的博客 2397

java 常驻线程_java并发编程学习: 守护线程(Daemon Thread)

在正式理解这个概念前,先把 守护线程 与 守护进程 这二个极其相似的说法区分开,守护进程通常是为了防止某些应用因各种意外原因退出,而在后台独立运行的系统服务或应用程序。 比如:我们开发了一个邮件发送程序,一直不停的监视队列池,发现有待发送的邮件,就将其发送出去。如果这个程序挂了(或被人误操作关了),邮件就不发出去了,为了防止这种情况,再开发一个类似windows 系统服务的应用,常驻后台,监制这个...

weixin_42354944的博客 1231

RTAB-map:实时高效的SLAM库

Real‐time appearance‐based mapping (RTAB‐Map)是一种基于外观的闭环检测方法,具有良好的内存管理,以满足处理大场景和在线长周期管理要求。RTAB‐Map集成了视觉和激光雷达SLAM方案,并支持目前绝大多数的传感器 是一个强大的、开源的Simultaneous Localization and Mapping(SLAM)库,专为机器人和无人驾驶领域设计。它提供了一套完整的解决方案,用于构建三维地图,并在未知环境中进行实时定位与导航。 github项目地址 RTAB-

weixin_45761399的博客 1万+

从仿真到实践:两级直接耦合放大电路的静态工作点协同调试指南

本文详细解析了两级直接耦合放大电路的静态工作点协同调试方法,从仿真到实践提供系统指南。重点介绍了Rc2电阻调整技巧、集电极电位测量方法及常见问题排查,帮助工程师解决各级静态工作点相互影响的难题,提升模拟电路设计效率。

weixin_29189373的博客 124

Java并发专题【2】线程的状态转换以及基本操作

作者:Java菜鸟奋斗史在上一篇文章中Java并发专题【1】并发编程的优缺点谈到了为什么花功夫去学习并发编程的技术,也就是说我们必须了解到并发编程的优缺点,我们在什么情况下可以去考虑开启多个线程去实现我们的业务,当然使用多线程我们应该着重注意一些什么,在上一篇文章中会有一些讨论。那么,说了这么多,无论是针对面试还是实际工作中作为一名软件开发人员都应该具备这样的技能。万事开头难,接下来就应该了解如何...

qq_40604853的博客 192

如何设计QR反激变换器

摘要:本文分析了基于GaN技术的PD适配器市场现状,重点探讨了准谐振反激变换器(QR Flyback)的工作原理及设计方法。文章首先介绍了反激变换器的三种工作模式(CCM、DCM、CRM/QR)及其特点,指出QR模式通过谷底开通技术能显著降低开关损耗。随后以65W适配器为例,详细阐述了变压器参数设计流程,包括匝比确定、原边电感计算和绕组匝数设计等关键步骤。文章强调QR反激变换器凭借高效率、小体积和低成本优势,已成为20W-65W PD适配器的主流拓扑方案,配合GaN技术进一步提升了功率密度和便携性。

m0_62868254的博客 1496

Java并发系列(2)线程状态转换以及基本操作

本站小福利 点我获取阿里云优惠券 原文作者:github:CL0610/Java-concurrency 免责声明: 1.本文所转载文章均来自公开网络。 2.如果出处标注有误或侵犯到原著作者权益,请联系删除。 3.转载文章请注明原文链接和作者,否则产生的任何版权纠纷均与本站无关。 在上一篇文章中并发编程的优缺点谈到了为什么花功夫去学习并发编程的技术,也就是说我们必须了解到并发编程的优缺点,我们在什...

不想当码农的程序员 297

iOS开发者必备:从越狱设备里提取IPA的三种方法(含Filza、iTools实战)

本文详细介绍了iOS开发者从越狱设备提取IPA文件的三种实用方法,包括使用Filza文件管理器、AFC2配合桌面工具以及命令行高级技术。内容涵盖环境准备、操作步骤和技术原理,帮助开发者高效获取应用包文件,适用于逆向工程、测试分析等场景。

weixin_28717969的博客 804

Vivado DDR IP自定义型号避坑指南:如何正确填写CSV参数表(附常见错误排查)

本文详细解析了Vivado DDR IP自定义型号配置中的关键步骤与常见问题,特别针对DDR4内存颗粒的参数提取、CSV参数表填写误区及故障排查提供了实用指南。通过实际案例和调试技巧,帮助工程师避免配置陷阱,提升DDR4系统稳定性和性能。

weixin_29280657的博客 413

《Java高并发程序设计》学习 --2.2 初始线程:线程的基本操作

1)新建线程 Java提供了线程类Thread来创建多线程的程序。其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象。每个Thread对象描述了一个单独的线程。要产生一个线程,有两种方法: ◆ 需要从Java.lang.Thread类派生一个新的线程类,重载它的run()方法;  ◆ 实现Runnalbe接口,重载Runnalbe接口中的run()方

sunhaoning的专栏 386

手把手带你搞懂电压跌落测试DIP

砖一用4分钟时间手把手带你搞懂电压跌落测试DIP,希望对你有用~

qq_45508321的博客 7916

【线程探秘】Java并发艺术

科大讯飞高级架构师十余年经验总结!自顶向下详解Java线程实现原理与实践《一本书讲透Java线程:原理与实践》推文赠书

优快云站内信: https://i.youkuaiyun.com/#/msg/chat/qyj19920704 2万+

[Python从零到壹] 十三.机器学习之聚类算法四万字总结全网首发(K-Means、BIRCH、树状聚类、MeanShift)

欢迎大家来到“Python从零到壹”,在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界。所有文章都将结合案例、代码和作者的经验讲解,真心想把自己近十年的编程经验分享给大家,希望对您有所帮助,文章中不足之处也请海涵。Python系列整体框架包括基础语法10篇、网络爬虫30篇、可视化分析10篇、机器学习20篇、大数据分析20篇、图像识别30篇、人工智能40篇、Python安全20篇、其他技巧10篇。您的关注、点赞和转发就是对秀璋最大的支持,知识无价人有情,希望

杨秀璋的专栏 2万+

高级数据结构之R树(R-tree)

R树(R-tree)是一种将B树扩展到多维情况下得到的数据结构,它最初由Antonin Guttman于1984年提出。B树的结点中会存储一个键的集合,这些键把线分成片段,沿着那条线的点仅属于一个片段。因此,B树使得我们可以很容易地找到点。如果把沿线各处的点表示成B树结点,我们就能够确定点所属唯一子结点,在那里可以找到该点。 Antonin Guttman在他提出R树的经典论文中给出的R树例子...

白马负金羁 1万+

JAVA多线程并发

JAVA多线程并发1 JAVA并发知识库2 JAVA 线程实现/创建方式2.1 继承 Thread 类2.2 实现 Runnable 接口2.3 Callable 、Future 、ExecutorService 有返回值线程2.4 基于线程池的方式2.4.1 4种线程池2.4.1.1 newCachedThreadPool2.4.1.2 newFixedThreadPool2.4.1.3 new...

ma815841356的博客 4842

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Java 并发和线程处理

大家好,我是默语,擅长全栈开发、运维和人工智能技术。在本篇博客中,我们将深入探讨 Java 并发和线程处理的最佳实践,特别是在多线程编程中如何确保线程安全性和避免死锁。理解并发编程的原理及应用场景,对于开发高效稳定的 Java 应用程序至关重要。通过这篇文章,您将全面掌握 Java 并发处理的核心技术,并学会如何在实际项目中有效应用这些技术。并发是指多个任务在同一时间段内执行,线程是操作系统能够独立执行调度的最小单位。在 Java 中,通过多线程编程可以实现并发任务的处理,提高程序的执行效率。

沉淀所学,分享所思,让热爱与成长同行。商务记录AI实战经验,助力开发者快速成长。 热爱AI,希望做出有影响力的技术成果。 技术点亮生活,分享连接价值与机会。 专注AI落地实战,陪你走好技术每一步。 5万+

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

线程的状态和基本操作

在上一篇博客中并发编程的优缺点谈到了为什么花功夫去学习并发编程的技术。万事开头难,接下来就应该了解如何新建一个线程?线程状态是怎样转换的?关于线程状态的操作是怎样的?这篇博客就主要围绕这三个方面来聊一聊。 文章目录创建线程的四种方式线程的状态和生命周期线程状态的基本操作interruptedjoinsleepyield进程和线程线程优先级守护线程和用户线程守护线程详解线程死锁认识线程死锁如何避免线...

ThinkWon的博客 1万+

Java并发与线程

Java并行与并发 转自己的学习笔记:2016-09-26 代码没有流程控制前提下,代码是从上而下逐行执行的。 若要打游戏和放音乐同时运行(多任务同时运行),要使用多进程或多线程来解决。 并行和并发: 并行:指两个或多个事件在同一时刻点发生;(微观) 并发:至两个或多个事件在同一个时间段内发生;(宏观) 在操作系统中,再多到程序环境下,并发性是指在一段时间内宏观上有多个程序在...

不畏夕阳的博客 3979

JAVA并发编程——Java线程

本文是Java多线程编程的基础篇,系统讲解了进程与线程的核心概念及实际应用。主要内容包括:进程与线程的区别与联系、并行与并发的本质区别、多线程在异步调用和效率提升中的应用场景。详细介绍了三种创建线程的方法(Thread、Runnable、FutureTask),并对比了它们的优缺点。文章还提供了查看进程线程的实用命令,解析了线程运行的底层原理(栈帧、上下文切换)。最后对常用线程方法(run/start/sleep/yield等)进行了深入讲解,帮助读者掌握多线程编程的基础知识。(14

weixin_52344200的博客 820

JAVA并发三:线程的状态转换以及基本操作

在上一篇文章中并发编程的优缺点谈到了为什么花功夫去学习并发编程的技术,也就是说我们必须了解到并发编程的优缺点,我们在什么情况下可以去考虑开启多个线程去实现我们的业务,当然使用多线程我们应该着重注意一些什么,在上一篇文章中会有一些讨论。那么,说了这么多,无论是针对面试还是实际工作中作为一名软件开发人员都应该具备这样的技能。万事开头难,接下来就应该了解如何新建一个线程?线程状态是怎样转换的?关于线程状...

今天的BUG保熟。 176

java并发和多线程

java 并发和多线程,理解基本概念和时间

weixin_47467016的博客 1360

Java并发系列二:线程的创建、状态转换及基本操作

在上一篇文章中Java并发专题【1】并发编程的优缺点谈到了为什么花功夫去学习并发编程的技术,也就是说我们必须了解到并发编程的优缺点,我们在什么情况下可以去考虑开启多个线程去实现我们的业务,当然使用多线程我们应该着重注意一些什么,在上一篇文章中会有一些讨论。那么,说了这么多,无论是针对面试还是实际工作中作为一名软件开发人员都应该具备这样的技能。万事开头难,接下来就应该了解如何新建一个线程?线程状态是...

TzBugs的博客 745

Java并发-线程状态转换以及基本操作

在上一篇文章中并发编程的优缺点谈到了为什么花功夫去学习并发编程的技术,也就是说我们必须了解到并发编程的优缺点,我们在什么情况下可以去考虑开启多个线程去实现我们的业务,当然使用多线程我们应该着重注意一些什么,在上一篇文章中会有一些讨论。那么,说了这么多,无论是针对面试还是实际工作中作为一名软件开发人员都应该具备这样的技能。万事开头难,接下来就应该了解如何新建一个线程?线程状态是怎样转换的?关于线程状态的操作是怎样的?这篇文章就主要围绕这三个方面来聊一聊。 1. 新建线程 一个java程序从main()方法开始

羊羊吃草 224
上一篇: java并发(1)——JVM原子性、可见性、有序性
下一篇: JVM的基本结构
sicofield
博客等级 码龄18年 169粉丝 169原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值