`
阅读更多
多线程


一,线程的一些基本知识。
进程与线程
所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中就是一个进程,当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程。

进程(process)
当一个程序进入内存运行即变成一个进程,进程处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调用的独立单位,进程切换开销大。

多进程
在操作系统中,能同时运行多个任务程序。

进程包含三大特征
1,独立性:
进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己私有的地址空间,没有经过进程本身允许的情况下,一个用户不可以直接访问其他进程的地址空间。
2,动态性:
进程与程序的区别在于程序只是个静态的指定集合,而进程是一个正在系统中活动的指定集合,在进程中加入了时间的概念,进程具有自己的生命周期和各种不同的状态,这些状态在程序中是不具备的。
3,并发性:
多个线程可以在单个处理器是并发执行多个进程,进程之间,不会互相影响。

注:
对于一个CPU而言,它在某个时间点上只能执行一个程序,就是说只能运行一个进程。CPU不断在这些进程之间轮回切换,CPU的执行速度相对于我们的感觉太快,我们感觉不到,所以CPU在多个进程之间轮回执行,但我们人类感觉好像多个进程同时执行。

线程(Thread)
线程被称为轻量级的进程,线程是进程的执行单元,就像进程在操作系统中的地位一样。线程在程序中是独立的,并发的执行的流。当进程被初始化后,主线程就被创建了,一般的应用程序来说,通常仅要求有一个主线程,但我们也可以在该进程内创建多条顺序执行流,这些顺序执行流就是线程,每条线程是相互独立的。

注:
总而言之,一个程序运行后,至少有一个进程,一个进程里可以包含多个线程,但至少要包含一个线程。

多线程(multithreading)
在同一个应用程序中,有多个顺序执行流同时执行。

线程比进程具有更高的性能,这是由于同一个进程中的线程都有共性,多个线程将共享同一个进程的虚拟空间,-线程共享的环境包括进程代码段,进程的公有数据等,利用这些共享的数据,线程很容易实现相互之间的通信。

当操作系统创建一个进程时,该进程必须分配独立的内存空间,分配大量相关资料,但创建一个线程简单的多,因此使用多线程来实现并发比使用多进程来实现并发的性能要高得多。

多线程的优点
1,进程之间不能共享内存,但线程之间共享内存非常容易。
2,系统创建进程需要为该进程重新分配系统资源,但创建线程代价要小的多,因此使用多线程来实现多个任务并发比多进程要效率高。
3,Java语言中内置多线程功能的支持,而不是单纯的作为底层的操作系统的调动方式,从而简化了Java的多线程编程。

二,线程的启动和创建
Thread类(Java.lang.Thread类)
在Java语言中Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每条线程的作用是完成一定的任务,实际上就是执行一段程序流,也叫一段顺序执行的代码,Java使用run方法来封装这样一段程序流。

继承Thread类创建和启动线程
1,定义Thread类的子类,并重写该类的run方法,该run方法的方法体就是代表了线程需要完成的任务,run方法也被称为线程执行体。
2,创建Thread类子类的实例,即创建了线程的对象。
3,用线程对象的start方法来启动该线程。

start()方法
使该线程开始执行,Java虚拟机调用该线程的run方法。
getName()方法
返回该线程的名称
setName(String name)方法
修改该线程的名称
interrupt();
中断线程
sleep(long millis);
在指定的毫秒内让当前正在执行的线程休眠.

1,实现Runable接口的实现类,并重写该接口的run方法,该run方法的方法体同样是该线程的执行体。
2,创建Runable实现类的实例,并以此实例作为Thread类的目标来创建Thread类的目标创建Thread对象,该Thread对象才是真正的线程对象。

Thread类和Runable接口创建线程的对比
继承Thread类方式的多线程的优点:
编写简单,如果访问当前线程,无需使用Thread.currentThread方法,直接使用this,即可获得当前线程。
继承Thread类方式的多线程缺点:
因为线程已经继承了Thread类,所以不能再继承其他的类。

实现Runable接口的优点:
线程只是实现了Runable接口,还可以继承其他的类,在这种方式下,可以多个线程共享同一个目标(target)对象,所以非常适合多个线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,体现了面向对象的思想。
实现Runable接口的缺点:
编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread方法。

三,线程的生命周期
当线程被创建并启动以后,它既不是一启动就进入了执行的状态,也不是一直处于执行状态,在线程的生命周期里,它要经过新建,就绪,运行,阻塞,死亡五种状态。尤其是当线程启动以后,它不能一直霸占着CPU独立运行,所以CPU多条线程之间切换,于是线程状态也会多次在运行和阻塞之间切换。

新建或就绪状态
启动线程使用start方法,而不是run方法,永远不用调用线程对象的run方法,调用start方法来启动线程系统会把该run方法当成线程执行体来处理。但如果直接调用线程对象的run方法,则run方法立即会被执行,而且在run方法返回之前其他线程无法并发执行,也就是说系统吧线程对象当成一个普通的对象,而run方法也是一个普通方法,而不是线程执行体。

当线程对象调用了start方法之后,该线程处于就绪状态,JVM会为创建方法调用栈和线程计数器处于这个状态中的线程,并没有开始运行,它只是表示该线程可以运行了,至于该线程何时开始运行,取决于JVM里线程调度器的调度。

运行和阻塞状态
如果处于就绪状态的线程获得了CPU资源,开始执行run方法的执行体,则该线程处于运行状态,当一条线程开始运行后,它不可能一直处于运行状态,线程在运行的过程中,需要被中断,目的是使其他线程获得执行的机会,当发生以下情况下,线程将会进入阻塞状态;
1,线程调用sleep方法主动放弃所占有的CPU资源。
2,线程调用一个阻塞式IO方法,该方法返回之前该线程被阻塞。
3,线程试图获得一个同步监视器,但该同步监视器正被其他线程所占据。
4,线程在等待某个通知(ntify,ntifyAll方法 在Objiet类里)。
5,程序调用了线程的suspend方法,将线程挂起暂停),不过这个方法容易导致死锁,所以程序尽量避免该方法。
线程重新进入就绪状态有以下情况:
1,调用sleep方法的线程经过指定的时间。
2,线程调用阻塞式IO方法已经返回。
3,线程成功的获得了试图取得同步监视器。
4,线程正在等待某个通知,其他线程发出了通知。
5,处于挂起状态的线程被调用了resume方法恢复。

注:
阻塞状态也叫不可运行状态
调用yield方法可以让当前运行的线程转入就绪状态。

线程会在以下三种方式之一结束线程,处于死亡状态:
1,run方法执行完成,线程正常结束。
2,线程抛出一个未捕获的Exception或Error。
3,直接调用线程的stop方法来结束该线程,该方法容易导致死锁,通常不推荐用。

isAlive方法
测试某条线程是否已经死亡,当线程处于就绪,运行,阻塞三种状态时,该方法返回true,当该线程处于创建,死亡两种状态时,该方法返回false。

注:
不要试图对一个已经死亡的线程调用start方法,使它重新启动,该线程将不可再次作为线程执行,它会抛出IllegaThreadStateException异常。

不要让处于死亡状态的线程调用start方法,程序只能对新建状态的线程调用start方法,对新建状态的线程两次调用start方法也是错误的。

join()方法
等待被join的线程执行完成。
join(long millis)方法
等join的新车的时间最长为minllis毫秒,如果在millis毫秒内被join的线程还没有执行结束,则不再等待。
join(long millis ,int nanos)方法
等待被join的时机最长为millis毫秒加nanos纳秒。


setPriority()和方法:
来设值和取值,
返回线程的优先级,其中setPriority可以是个整数,范围是一到十之间,也可以是MAX_PRIORITY ,MIN_PRIORITY ,NORM_PRIORITY 三个静态常量。
getPriority()方法
返回线程的优先级。每个线程执行时,都具有一定的优先级,优先级高的线程获得较多的执行机会,而优先级低的线程则获得较小的执行机会。

后台线程(DaemonThread)
有一种线程它是在后台运行的,它的任务是为其他线程提供服务,这种线程称为后台线程,又称为守护线程,又称为精灵线程。JVM的垃圾回收线程就是典型的后台线程。后台线程有个特征:如果所有的前台线程都死亡,后台线程会自动死亡。调用Thread对象的setDaemon(blooean on)方法(参数传true),可将指定线程设置为后台线程,isDaemon()判断该线程是否为后台线程,如果该线程是守护线程,则返回 true;否则返回 false。

sleep(long millis)方法(线程睡眠)
让当前正在执行的线程暂停并进入阻塞状态,该方法受到系统计时器和线程调度器的精度和准确度的影响。

注:
当前线程调用sleep方法,进入阻塞状态后,在sleep时间段内,该线程不会获得执行的机会,即使系统中没有其他可运行的线程,处于sleep时间段里的线程也不会运行。因此sleep常用来暂停程序的执行,


yield()方法(线程让步)
yield方法和sleep有点相似的方法,让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态,yield方法只是让当前线程暂停一下,让系统的线程调度器从新调度一次,当某个线程调用了yield方法暂停之后,只有优先级与当前线程相同,或者优先级比当前线程更高的就绪状态的线程才会获得执行的机会


sleep方法和yield方法的区别
1,sleep方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级,但yield方法只会给优先级相同或优先级更高的线程执行机会。
2,sleep方法会将线程转入阻塞状态,直到经过阻塞时间,才会转入就绪状态,而yield方法不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态,因此完全有可能某个线程用yield方法暂停之后立即再次获得处理器资源被执行。
3,sleep方法声明抛出 InterruptedException 异常。所有调用sleep方法时,要么扑捉该异常,要么显示声明抛出该异常。而yield方法则没有声明抛出任何异常。
4,sleep方法比yield方法有更好的可移植性,通常不用依靠yield方法来控制并发线程的执行。


interrupt()
使该线程中断,如果一个线程抛出异常,可以用interrupt在catch里中断该线程.


Thread()
          分配新的 Thread 对象。
Thread(Runnable target)
          分配新的 Thread 对象。
Thread(Runnable target, String name)
          分配新的 Thread 对象。
Thread(String name) 


static Thread currentThread()
          返回对当前正在执行的线程对象的引用。

String getName()
          返回该线程的名称。

void setName(String name)
          改变线程名称,使之与参数 name 相同。

int getPriority()
          返回线程的优先级。
void setPriority(int newPriority)
          更改线程的优先级。

void interrupt()
          中断线程。

boolean isAlive()
          测试线程是否处于活动状态。

boolean isDaemon()
          测试该线程是否为守护线程。

void join()
          等待该线程终止。
void join(long millis)
          等待该线程终止的时间最长为 millis 毫秒。

void run()
          如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。

void setDaemon(boolean on)
          将该线程标记为守护线程或用户线程。

void start()
          使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

static void yield()
          暂停当前正在执行的线程对象,并执行其他线程。


ThreadGroup类
ThreadGroup类来表示线程组,它可以对一批线程进行分类管理。Java允许程序直接对线程组进行控制,


线程同步
Java里的多线程编程常常容易突然出现错误情况,这是由于系统的线程调度具有一定随机性,即使程序在运行过程中偶尔出现问题,是由于我们编程不当所引起的。当使用多个线程来访问同一个数据时,非常容易出现线程安全问题,所以我们用同步机制来解决这些问题。

实现同步机制有两个方法:
1,同步代码块:
synchronized(同一个数据){}    同一个数据:就是N条线程同时访问一个数据
2,同步方法:
public synchronized 数据返回类型 方法名(){}
就是使用 synchronized 来修饰某个方法,则该方法称为同步方法。对于同步方法而言,无需显示指定同步监视器,同步方法的同步监视器是 this 也就是该对象的本身,通过使用同步方法,可非常方便的将某类变成线程安全的类,具有如下特征:
1,该类的对象可以被多个线程安全的访问。
2,每个线程调用该对象的任意方法之后,都将得到正确的结果。
3,每个线程调用该对象的任意方法之后,该对象状态依然保持合理状态。
注:synchronized关键字可以修饰方法,也可以修饰代码块,但不能修饰构造器,属性等。

实现同步机制注意以下几点:   安全性高,性能低,在多线程用。性能高,安全性低,在单线程用。
1,不要对线程安全类的所有方法都进行同步,只对那些会改变共享资源方法的进行同步。
2,如果可变类有两种运行环境,当线程环境和多线程环境则应该为该可变类提供两种版本:线程安全版本和线程不安全版本(没有同步方法和同步块)。在单线程中环境中,使用线程不安全版本以保证性能,在多线程中使用线程安全版本.


Java.lang.object 里的三个方法wait() notify()  notifyAll()
wait方法导致当前线程等待,直到其他线程调用同步监视器的notify方法或notifyAll方法来唤醒该线程。
wait(mills)方法
都是等待指定时间后自动苏醒,调用wait方法的当前线程会释放该同步监视器的锁定,可以不用notify或notifyAll方法把它唤醒。

notify()
唤醒在同步监视器上等待的单个线程,如果所有线程都在同步监视器上等待,则会选择唤醒其中一个线程,选择是任意性的,只有当前线程放弃对该同步监视器的锁定后,也就是使用wait方法后,才可以执行被唤醒的线程。

notifyAll()方法
唤醒在同步监视器上等待的所有的线程。只用当前线程放弃对该同步监视器的锁定后,才可以执行被唤醒的线程。
分享到:
评论

相关推荐

    大漠多线程模板_大漠_大漠多线程_

    "大漠多线程模板"是一个专门针对C#开发的多线程处理框架,它为开发者提供了便捷的方式来管理和优化多线程应用。这个框架由知名开发者"大漠"创建,旨在简化复杂的并发编程,提高代码的可读性和可维护性。 多线程允许...

    多线程_按键精灵经典多线程操作_

    在IT行业中,多线程是一种常见的编程技术,它允许程序同时执行多个独立的任务,从而提高计算机系统的效率和响应性。特别是在自动化工具如“按键精灵”中,多线程的应用能够显著提升其性能和实用性。 标题“多线程_...

    pb9多线程控件,能够真实实现多线程

    标题中的“pb9多线程控件”指的是在PowerBuilder 9.0(PB9)环境中,使用的一种能够实现真正多线程功能的组件或技术。PowerBuilder是一款经典的面向对象的开发工具,主要用于构建数据库应用系统。在PB的早期版本中,...

    C#多线程互斥实例 多线程获取同一变量

    在编程领域,多线程是实现并发执行任务的重要机制,特别是在现代计算机系统中,多核处理器使得多线程成为提高程序性能的关键手段。C#语言提供了丰富的多线程支持,让我们能够编写出高效的多线程应用程序。在这个"多...

    多线程编程示例

    在IT领域,多线程编程是一项关键技能,尤其是在性能优化和并发处理方面。本文将深入探讨多线程编程的基础知识,以帮助初学者快速入门。 首先,我们需要理解什么是多线程。多线程是指在一个进程中同时执行多个独立的...

    易语言多线程传递多参数

    在编程领域,多线程是实现并发执行任务的重要机制,特别是在易语言中,它能有效提升程序的执行效率。易语言是一种中文编程语言,旨在降低编程门槛,让普通用户也能进行程序开发。本文将深入探讨易语言中的多线程以及...

    基于SpringBoot和POI实现单线程和多线程导出Excel.zip

    基于SpringBoot和POI实现单线程和多线程导出Excel.zip基于SpringBoot和POI实现单线程和多线程导出Excel.zip基于SpringBoot和POI实现单线程和多线程导出Excel.zip基于SpringBoot和POI实现单线程和多线程导出Excel.zip...

    C#.NET多线程实例6个(包括多线程基本使用,多线程互斥等全部多线程使用实例),可直接运行

    在.NET框架中,C#语言提供了强大的多线程支持,使得开发者可以充分利用现代多核处理器的优势,实现并行处理和高效能编程。本资源包含六个C#.NET多线程的实例,涵盖了多线程的基本使用到更高级的概念,如线程互斥。...

    多线程基础与基于多线程的简单聊天室

    在IT行业中,多线程是程序设计中的一个重要概念,尤其在Java编程中,它被广泛应用于提高应用程序的并发性能和响应速度。本压缩包“多线程基础与基于多线程的简单聊天室”提供了对多线程技术的实践理解和二次开发的...

    12.1 Qt5多线程:多线程及简单实例

    在编程领域,尤其是在开发高效、响应迅速的应用程序时,多线程技术扮演着至关重要的角色。Qt5框架提供了一种方便的方式来实现多线程,它允许开发者在不同的线程中执行任务,从而避免主线程(GUI线程)因处理耗时操作...

    PB多线程实现

    本文将详细探讨PB(包括PB9、PB12.5以及PB.NET)实现多线程的方法。 一、PB9的多线程实现 在PB9中,虽然官方并未直接支持多线程,但开发者可以通过使用Windows API函数来实现。一种常见的方式是创建一个新的窗口类...

    鱼刺多线程模块

    "鱼刺多线程模块"是一个专为提升程序运行效率而设计的开源组件,它主要聚焦于多线程技术的应用。在计算机科学中,多线程是并发执行多个任务或子任务的一种方法,使得程序能够更高效地利用系统资源,特别是在多核...

    Qt 多线程及简单实例 demo

    Qt 多线程及简单实例 demo。 多线程的几大特点: 1.多线程的执行顺序无法保证,与操作系统的调度策略和线程优先级等因素有关。 2.多线程的切换可能发生在任何时刻、任何地点。 3.多线程对代码的敏感度高,因此对...

    Linux下C语言多线程编程实例

    Linux 下 C 语言多线程编程实例 Linux 下的多线程编程是一种非常重要的技术,在实际应用中有非常广泛的应用范围。多线程编程可以大大提高程序的执行效率和响应速度。但是,多线程编程也存在一些复杂性,例如线程...

    单线程与多线程的区别

    单线程和多线程是计算机程序执行时的两种不同模型,它们在处理并发任务、资源管理和性能上有着显著的差异。理解这两种模型是编程尤其是服务器端开发的基础,尤其是在Java、C#等支持多线程的编程语言中。 首先,让...

    delphi多线程调用dll

    在Delphi编程中,多线程技术被广泛用于提高应用程序的执行效率,特别是在处理大量数据或执行长时间操作时。DLL(动态链接库)是Windows操作系统中的一个重要组件,它允许代码和资源在多个程序之间共享。当需要在多...

    C#多线程读写sqlite

    在C#编程中,多线程技术常用于提高应用程序的执行效率,特别是在处理数据库操作时。SQLite是一款轻量级、嵌入式的关系型数据库,它广泛应用于桌面应用、移动设备和Web开发。当多线程环境对SQLite进行读写操作时,...

    Qt中利用OpenCV2.4.4多线程打开多摄像机

    Qt中利用OpenCV2.4.4多线程打开多摄像机 每个线程处理一个摄像机,从中拿出帧显示到主线程的Label控件上 模拟了一个16个摄像机的场景,有不开多线程和打开多线程的对比。 可以明显感觉到打开多线程后主界面不卡了。 ...

    可并行递归算法的递归多线程实现

    ### 可并行递归算法的递归多线程实现:深入解析 #### 引言:多线程与并行处理的重要性 随着计算任务日益复杂,传统的单线程编程模型已无法满足高效处理大规模数据的需求。多线程编程作为一种提高程序并发性和性能...

    鱼刺多线程注册源码例子(鱼刺多线程稳定框架)

    "鱼刺多线程注册源码例子"是一个基于"鱼刺多线程稳定框架"的编程实践,旨在展示如何在软件开发中有效地利用多线程技术来提高程序的执行效率和稳定性。在这个例子中,"鱼刺框架"可能是一个专门为多线程编程设计的开源...

Global site tag (gtag.js) - Google Analytics