热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

qt多线程编程

本文主要分享【qt多线程编程】,技术文章【多线程编程】为【咸鱼吐泡泡】投稿,如果你遇到JAVA相关问题,本文相关知识或能到你。qt多线程编程        多线程指的是一个程序中包含两个或者两个以

本文主要分享【qt多线程编程】,技术文章【多线程编程】为【咸鱼吐泡泡】投稿,如果你遇到JAVA相关问题,本文相关知识或能到你。

qt多线程编程

        多线程指的是一个程序中包含两个或者两个以上的线程,多线程的提出是为提高代码的执行效率,这就好比工厂中的流水线,只有一条称为单线程,有多条流水线就成为多线程。多线程提高效率的同时由于并发执行的不确定性,导致出现的结果很多是我们不想要的,所以为了得到我们想要的结果就会在编写多线程的时候加入各种锁,其中最重要的就是synchronized和volatile。在认识它们之前现从多线程最基本的开始。

目录

一:线程的创建

1.基于类继承Thread创建线程 

2.基于实现Runnable接口的方式创建线程

3.基于匿名内部类继承Thread创建线程

4.基于匿名内部类实现Runnable接口创建线程

5.基于lambda表达式创建Runnable子类对象创建线程 

多线程中Thread的常见方法

多线程的特点

二:多线程的中断

中断一个线程有两种方式

通过共享的boolean类型的变量来中断线程

通过调用Thread里面的interrupt()方法来中断线程 

interrupt()的两个行为

三:多线程的等待

join方法

join的行为

join(long millis)方法

四:多线程的休眠

sleep的本质

五:获取多线程实例


一:线程的创建

这里有一个面试题:线程的创建方式有几种,答案一共是7中。下面讲现阶段能接触到的创建方式

1.基于类继承Thread创建线程 
public class Thread01 {
    public static void main(String[] args) {
        Mythod mythod = new Mythod();
        Thread thread = new Thread(mythod);
        thread.start();
    }
}
class Mythod extends Thread{
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("你好");
        }
    }
}
2.基于实现Runnable接口的方式创建线程
public class Thread02 {
    public static void main(String[] args) {
        t t = new t();
        Thread thread = new Thread(t);
        thread.start();
    }
}
class t implements Runnable{
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("再将");
        }
    }
}
3.基于匿名内部类继承Thread创建线程
public class Thread03 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("背景");
                }
            }
        };
        thread.start();
    }
}
4.基于匿名内部类实现Runnable接口创建线程
public class Thread04 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("李华");
                }
            }
        }).start();
    }
}
5.基于lambda表达式创建Runnable子类对象创建线程 
public class Thread05 {
    public static void main(String[] args) {
        new Thread(()->{
            while(true){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("韩梅梅");
            }
        }).start();
    }
}

还有两种是基于Callable/FutureTask的方式创建、基于线程池的方式创建

 

多线程中Thread的常见方法
getName()                        获得线程的名字(在创建线程的时候可以给线程起名字)
isDaemon()                       判断线程是否为守护线程(判断是否为后台线程)
isInterrupted                    判断线程是否被中断
public class Thread06 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                    
            }
        }, "我的线程");
        thread.start();
        System.out.println(thread.getName());
        System.out.println(thread.isDaemon());
        System.out.println(thread.isInterrupted());
    }
}

setDaemon()                      将线程设置为后台线程

一个线程被创建出来默认就是前台线程,前台线程会阻止进程的结束,而后台线程则不会,后台线程一结束进程就结束了,因此可以将前台线程设置为后台线程,从而提高程序的执行速度。

public class Thread06 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    System.out.println("你好");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread.start();
        System.out.println("程序已经结束");
    }
}

 

这里先出的“程序已经结束”再输出的“你好”体现出来多线程并发执行的不确定性,这个不确定性和操作系统的实现相关。可以看到进程并没有结束,原因是应为thread是一个前台线程,进程只有等待所有前台线程都结束以后才会结束。为了结束进程,只需要在开启thread线程之前将它设置为后台线程即可。

        thread.setDaemon(true);

 

 

 

多线程的特点

1.每个线程都是一个单独的执行流

2.每个线程之间是“并发”执行的,每个线程之间的执行顺序和操作系统的具体实现有关

3.多个线程执行的时间不是一个线程的1/n的原因是因为:创建线程自身也是有开销的,多个线程cpu上不一定是纯并行,也可能并发执行 

面试题:请分别从方法及运行结果说明Thread类中run和start的区别 

方法的区别:直接调用run方法,并没有创建新的线程,而只是之前的线程中(主线程),执行了run里面的内容;使用start则是创建了新的线程,新的线程里面调用的run方法。运行结果的区别:如果直接运行run方法,程序会等待run方法(方法里面写了个死循环)执行完毕以后才会执行其他线程,但是运行start则是线程之间的并发执行,输出的结果也是交替出现的。
class MyThread extends Thread{
    @Override
    public void run() {
        while(true){
            System.out.println("再见");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Thread01 {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("你好");
        }

    }
}

 运行的结果:

class MyThread extends Thread{
    @Override
    public void run() {
        while(true){
            System.out.println("再见");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Thread01 {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.run();
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("你好");
        }

    }
}

 运行结果:

二:多线程的中断 中断一个线程有两种方式 通过共享的boolean类型的变量来中断线程

中断线程就是让线程尽快将入口方法执行结束(入口方法:继承Thread重写run、实现Runnable接口重写run) 

public class Thread07 {
    private static boolean flag = true;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(){
            @Override
            public void run() {
                while(flag){
                    try {
                        System.out.println("你好");
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();
        Thread.sleep(3000);
        flag = false;
        System.out.println("线程已经被中断");
    }
}

 

通过调用Thread里面的interrupt()方法来中断线程 
public class Thread08 {
    public static void main(String args[]) throws InterruptedException {
        Thread thread = new Thread(){
            @Override
            public void run(){
                while(!Thread.currentThread().isInterrupted()){
                    try {
                        System.out.println("你好");
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();
        Thread.sleep(3000);
        thread.interrupt();
        System.out.println("线程被中断");
    }
}

 

在分析结果之前,先明白下面d的方法:

Thread.currentThread().isInterrupted()方法

上面的这个方法是Thread类里面的静态方法,Thread.currentThread()表示获取当前线程的实例也就是线程对象。isInterrupted()方法为修改线程内置的标志位,它默认的结果是true,因此在while里面使用时注意取反。

interrupt()的两个行为

1. 如果thread线程没有处于阻塞状态,此时的interrupt就会修改内置的标志位

2.如果thread线程正处于阻塞状态,此时的interrupt就让线程内部产生阻塞的方法,在这个例子中就是sleep方法抛出异常

 

因此我们看到的结果首先是thread里面执行了三秒,然后调用interrupt方法,此时thread线程刚好处于阻塞状态,因此就让sleep方法抛出异常。但是由于catch语句里面并没有退出的逻辑,所以thread还会一直执行

为了看到interrupt()方法的打断效果,有两种方式:

第一种就是不要interrupt()方法前面的休眠操作,因为多线程是抢占式的执行,一旦让interrupt()方法成功将while里面的标志位变为false则thread就退出了。

第二种就是在catch代码块中写退出的逻辑

第二种方式是我们主要使用的,因为我们可以在catch代码块中写相应的逻辑语句,可以让thread线程立即退出,也可以让它待会推出或者是永远不退出。 

 

三:多线程的等待

因为多线程的执行顺序是不确定的,为了让某一个线程有明确的的执行顺序,这里可以使用线程等待机制。

join方法

join方法主要用来等待线程结束

现在要求t1线程先执行,然后t2线程在执行:看如下代码

public class Thread09 {
    public static void main(String[] args) {
        System.out.println("main_beg");
        Thread t1 = new Thread(()->{
            System.out.println("t1_beg");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1_end");
        });

        Thread t2 = new Thread(()->{
            System.out.println("t2_beg");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t2_end");
        });
        t1.start();
        t2.start();
        System.out.println("main_end");
    }
}

 

 

可以看出代码的执行顺序是乱的,这样的结果往往是我们在编程中不想要的,我们作为编程者,需要的就是确定的结果。

为了获得准确的结果就要引入join,方法就是分别在t1.start()和t2.start()下面加入t1.join()、t2.join()

 

join的行为

1.如果被等待的线程还没执行完就阻塞等待

2.如果被等待的线程已经执行完了,直接就返回

3.main的阻塞等待时间是所有线程执行时间的总和

join(long millis)方法

和join一样,只不过这是有时间的等待,等不到就直接走了。

 

四:多线程的休眠

这个也已经在前面多次看到了,方法就就不讲了,主要讲一下sleep的本质。

sleep的本质

和sleep一样的让线程等待的方法还有wait/join/等待锁...它们的本质是把线程在PCB中的队列从就绪状态移到阻塞状态。时间到了或者出发了中断就会有回到就绪队列。

五:获取多线程实例

Thread.currentThread获得当前线程的实例

可以应用到下面三种形式的线程中:

public class Thread10 {
    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run(){
                System.out.println(Thread.currentThread().getId());
                System.out.println(this.getId());
            }
        };
        thread.start();
    }
}

结果都是12。如果是继承Thread方式创建的继承,Thread.currentThread获得的对象实例就是当前的对象thread,因此可以用this来代替

但是利用实现Runnable接口和创建lamdba的方式创建线程就不能用this,this得到的不是当前对象的实例。

本文《多线程编程》版权归咸鱼吐泡泡所有,引用多线程编程需遵循CC 4.0 BY-SA版权协议。


推荐阅读
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 本文介绍了协程的概念和意义,以及使用greenlet、yield、asyncio、async/await等技术实现协程编程的方法。同时还介绍了事件循环的作用和使用方法,以及如何使用await关键字和Task对象来实现异步编程。最后还提供了一些快速上手的示例代码。 ... [详细]
  • 第七课主要内容:多进程多线程FIFO,LIFO,优先队列线程局部变量进程与线程的选择线程池异步IO概念及twisted案例股票数据抓取 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
  • 在开发中,有时候一个业务上要求的原子操作不仅仅包括数据库,还可能涉及外部接口或者消息队列。此时,传统的数据库事务无法满足需求。本文介绍了Java中如何利用java.lang.Runtime.addShutdownHook方法来保证业务线程的完整性。通过添加钩子,在程序退出时触发钩子,可以执行一些操作,如循环检查某个线程的状态,直到业务线程正常退出,再结束钩子程序。例子程序展示了如何利用钩子来保证业务线程的完整性。 ... [详细]
  • 深入理解线程、进程、多线程、线程池
    本文以QT的方式来走进线程池的应用、线程、进程、线程池、线程锁、互斥量、信号量、线程同步等的详解,一文让你小白变大神!为什么要使用多线程、线程锁、互斥量、信号量?为什么需要线程 ... [详细]
  • 我所理解的JMM 2 new原子性
    概述文本探讨构造函数是否为原子性问题。案例我们首先如下代码:publicclassPerson{publicintage;publicPerson(){age ... [详细]
author-avatar
mobiledu2502905597
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有