`
student_lp
  • 浏览: 436516 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java多线程、资源共享和死锁

阅读更多

一、进程和线程的概念和区别

      进程是一块包含了某些资源的内存区域。操作系统利用进程把它的工作划分为一些功能单元,并且进程中包含一个或多个执行单元称为线程(thread)。进程还拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问,是系统进行资源分配和调度的一个独立单位。

     线程是操作系统分配处理器时间的基本单元,可以有多个线程同时执行代码,且多个线程共享内存。但每个线程都维护异常处理程序、调度优先级和一组系统用于在调度该线程前保存线程上下文的结构。线程上下文包括为使线程在线程的宿主进程地址空间中无缝地继续执行所需的所有信息,包括线程的 CPU 寄存器组和堆栈。

二、编写多线程

       线程的活动都是通过线程的run()方法来实现的。在一个线程被创建并初始化后,java的运行时系统就会自动调用run()方法,正式通过run()方法才使得建立线程的目的得以实现。线程开始时,从run()开始执行,这就是线程执行的起始点。就像应用程序从main()开始一样。

     通常run()方法总是某种形式的循环,使得任务一直运行下去直到不再需要。一般情况下,我们会设定跳出循环的条件,如果系统一直不能满足我们设定的跳出条件,run()会永远的运行下去。

    下面来具体讲讲多线程是如何实现的:

1、通过实现一个Runnable接口

    线程可以驱动任务,因此我们可以通过描述任务的方式,这可以由Runnable接口来提供。要想定义任务,只需要实现Runnable接口并编写run()方法,这就使得任务可以执行你的命令,如:

    public  class  myThread  implements  Runnable{  

          public void run(){

               while(true){

                      ...  ...

               }

          }

    }

在使用的时候,执行要实现这个类,然后调用run()方法就是了。

2、通过继承Thread类的方式

      我们可以通过建立一个Thread的子类,通过继承Thread并覆盖其run()方法来构造线程体,使其能充分按自己的吩咐行事。在这里,run()属于那些会与程序中的其他线程“并发”或“同时”执行的代码。Thread 包含了一个特殊的方法,叫作 start(),它的作用是对线程进行特殊的初始化,然后调用 run()。

      整个步骤包括:调用构建器来构建对象,然后用 start()配置线程,再调用 run()。如果不调用 start()——如果适当的话,可在构建器那样做——线程便永远不会启动。注意:每个线程都会“注册”自己,即使没有显示的通过句柄对其引用,在运行的过程中,垃圾回收期也不能对这个类进行回收。例子如下:

     public  class  myThread extends Thread{

               public myThread(String  str){

                       super(str);

               }

               public void run(){

                      ... ...

               }

     }

     myThread thread = new MyThread("1");thread.start();

两种方法的比较:①直接继承Thread类:不能再从其他类继承,但编写简单,可以直接操作线程;

②通过实现Runnable接口构造线程体:可以讲CPU、代码和数据分开,形成清晰的模型;还可以继承其他类;保持程序分隔的一致性。

三、线程的状态

       在一个线程的生命周期中,他总是处于某一状态中。线程的状态表示了线程正在运行的活动以及这段时间内线程能完成的任务。线程的状态有:①创建状态(new Thread)②可运行状态(Runnable)③运行状态(Running)④不可运行状态(not Runnable)⑤死亡状态(dead)⑥非法状态异常(lllegalThreadStateException).


①创建状态:他仅仅是一个空的线程对象,系统不为它分配资源;

②可运行状态:系统为这个线程分配了他所需要的资源,安排其运行并调用线程运行方法,这样就使的线程处于可运行状态。需要注意这一状态并不是运行中,以为线程实际上并未真正的运行(很多计算机都是单核的,所以同一时刻所有处于可运行状态的线程都在运行时不可能的)。

③运行中:当一个线程处于可运行状态,并且系统为他分配了他所需要的一些资源,java的运行系统调度选中一个可运行状态的线程,开始执行。

④不可运行状态:也称为堵塞状态(Blocked)。由于某种原因,系统不能执行线程的状态。这时即使处理器空置,也不能执行。具体的原因可能有以下几种:调用了sleep(),但休眠完成后线程进入可运行状态等待重新调度;为等候一个条件变量,线程调用了wait()方法,当满足这个变量后,变量所在的对象调用notify()或notifyAll()方法,唤醒线程进入可运行状态;输入输出流发生线程阻塞,则需要等待阻塞的结束;

⑤死亡状态:线程执行结束,存在两种情况:自然撤销或被停止。自然撤销是自动退出;被停止是所属应用程序(进程)停止运行。

⑥非法状态异常:但一个线程创建后,只能在对应的某个状态进行允许的操作,如果操作不当就会引起非法状态。

四、线程的调度和优先级

       虚拟CPU通过使每个线程工作若干步,实现多线程同时运行的。决定实际CPU在那个时刻实际执行那个线程的方法称为线程调度模型。在java中,这个模型与平台有关。

      在java中,java提供了一个线程调度器来监控线程中启动后可以进入运行状态的全部线程。线程调度器按照线程优先级的高低选择优先级高的线程执行,同时线程调度是先占式调度,即如果当前线程执行过程中,一个更高优先级的线程进入可运行状态,则这个线程立即被调度执行。先占式调度由分为:独占方式和分时方式。

1、调度方式

①独占方式:在这个方式下,当前执行线程将一直运行下去,直到执行完毕或由于某种原因主动退出放弃cpu,或者一个更高优先级的线程进入可运行状态。

②分时方式:在这种方式下,当前运行线程执行当前时间片后,如果有可运行状态的线程,系统将选中其他可运行状态的线程执行,当前线程进入可运行状态,等待下一个时间片的调度。

2、线程优先级

       线程的优先级将该线程的重要度传递给了调度器。尽管CPU处理现有线程集的顺序是不确定的,但是调度器更倾向于让优先权最高的线程先运行。然而,这并不意味着优先权较低的线程将得不到运行,优先级低的线程仅仅是执行的频率较低。

       线程的优先级用数字表示,范围从1到10,即Thread.MIN_PRIORITY到Thread.MAX_PRIORITY。一个线程的默认优先级为5。我们可以通过getPriority()方法获得线程的优先级;也可以通过setPriority()方法设置线程的优先级:

    public final  void  setPriority(int newPriority);

    public final  int   getPriority();

 五、线程的调度方法

       在线程中提供了很多方法,通过这些方法,可以影响线程的运行状态。为了理解这些方法,我们通过一个线程状态变迁图说明:


 六、有关线程的其他一些概念和方法

1、后台线程(Daemon)

      后台线程(Daemon)是指程序运行时在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此,当所有非后台线程结束时,程序也就终止了,同时杀死了进程中所有后台线程。反过来说,只要有任何非后台线程还在运行,后台线程就不会终止。

     后台线程必须在线程启动(start)之前调用setDaemon()方法,才能把它设置为后台线程。

2、同步(synchronized)

      java中每个对象都对应于一个称为“互斥锁”的标志,这个标志用来保证在任何时刻,只能有一个线程访问该对象。如果系统中的资源当前没有被使用,线程可以得到“互斥锁”,即线程可以得到资源的使用权。当线程执行完毕后,他放弃“互斥锁”,如果一个线程获得“互斥锁”时,其余的线程就必须等待当前线程结束并放弃“互斥锁”。

      在java中,提供了关键字synchronized来实现对象的“互斥锁”关系。当某个对象或方法用关键字synchronized修饰时,表明该对象或方法在任何一个时刻只能有一个线程访问。如果synchronized用在类的生命中,表明该类中的所有方法都是synchronized的。

3、线程组(ThreadGroup)

       每个线程都是一个县城组的成员,线程组把多个线程集成为一个对象,通过线程组可以同时对其中的多个线程进行操作,如启动一个线程组中的所有线程。java线程组是由ThreadGroup实现。

       类ThreadGroup用来管理一个线程组,包括线程数目,线程间的关系,线程正在执行的操作,以及线程将要启动或终止的时间等。线程组中还可以包含线程组,形成线程组和线程组之间的树状关系。

七、资源的同步与共享

       前面的例子提到的线程都是独立的,而且是异步执行,也就是每个线程都包含了运行所需的一切资源,而不再需要外部资源和方法,也不关心其它线程状态和行为。但是很多时候,同时运行的线程需要共享一些数据,比如同时对一个文件读写。这就必须考虑其他线程的行为和状态,这时就需要实现同步来的预期的结果。

      为了解决资源共享的问题。我们通常采用下面一些方法来解决:

      ①使用前面介绍的synchronized,将需要共享的资源进行标记(互斥锁)的方法,防止资源冲突;

      ②显示的Lock对象。在java se5的java.util.concurrent类库包含concurrent.locks中显示的互斥机制。Lock对象必须被显示的创建、锁定和释放。因此,他与内建的锁形式相比,代码缺乏有雅性。但是,对于解决某些类型的问题来说,他更加灵活。

     以上是常用的集中方式,如果有需要这部分知识,需要深入研究,我这里只提供一个方向:原子性和易变性的探讨;原子类(如AtomicInteger、TtomicLong);临界区;在其他对象上同步;线程本地存储;

八、死锁问题

      为了防止数据并发访问,引用线程共享的对象(条件变量)时,为使数据操作能保持一致性,应设互斥区,进行互斥操作。进入互斥去操作数据,必须先获得互斥锁的使用权。

      如果程序中多个线程互相等待对方自愿,而在得到对方资源之前都不会释放自己的资源,这就造成都想得到资源而又得不到,线程就不能继续前进,这就是死锁问题。当然还会有其他死锁类型。但这主要是开发人员不小心造成的。

     java技术既不能发现死锁也不能避免死锁。只能依靠程序员自己注意。但这里有一个设计规则:线程因为某个先决条件未满足而受阻,不能让其继续占有资源。如果多个对象需要互斥访问,应确定线程获得锁的一个顺序,并保证贯穿整个程序,并以相反的方向释放锁。

     

 

 

  • 大小: 62.2 KB
  • 大小: 67.6 KB
分享到:
评论

相关推荐

    java多线程死锁预防机制研究

    通过对Java多线程环境下死锁现象的研究,我们可以发现,通过合理的设计和实施预防策略,可以有效避免死锁的发生。特别是在现代软件开发中,正确地使用锁机制,不仅可以提高程序的执行效率,还能确保系统的稳定性和...

    java多线程的讲解和实战

    Java多线程是Java编程中的重要概念,尤其在如今的多核处理器环境下,理解并熟练掌握多线程技术对于提高程序性能和响应速度至关重要。本资料详细讲解了Java多线程的原理,并提供了丰富的实战代码,非常适合Java初学者...

    Java多线程技术 线程的死锁,详细阐述了多线程的两种实现方法: 由Thread类派生子类;实现Runnable接口

    ### Java多线程技术详解 #### 一、引言 多线程编程是现代软件开发中不可或缺的一部分,尤其是在Java这样的面向对象编程语言中尤为重要。Java提供了丰富的API支持多线程编程,使得开发者能够轻松地创建复杂的并发...

    java多线程经典案例

    Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,极大地提升了程序的效率和性能。在Java中,实现多线程有两种主要方式:通过实现Runnable接口或者继承Thread类。本案例将深入探讨Java多线程中的关键...

    java模拟线程死锁

    在 Java 中,线程死锁(Deadlock)是一种特殊的情况,发生在两个或多个线程之间的互相等待对方释放资源的状态。这种情况下,各个线程都在等待其他线程释放资源,而自己也占用着其他线程需要的资源,从而导致所有线程...

    JAVA多线程编程技术PDF

    这份“JAVA多线程编程技术PDF”是学习和掌握这一领域的经典资料,涵盖了多线程的全部知识点。 首先,多线程的核心概念包括线程的创建与启动。在Java中,可以通过实现Runnable接口或继承Thread类来创建线程。创建后...

    java 多线程并发实例

    在Java编程中,多线程并发是提升程序执行效率、充分利用多核处理器资源的重要手段。本文将基于"java 多线程并发实例"这个主题,深入探讨Java中的多线程并发概念及其应用。 首先,我们要了解Java中的线程。线程是...

    Java多线程详解及示例

    Java多线程编程是提升程序性能和响应性的关键技术。理解多线程的概念,掌握线程的创建、同步、通信、死锁避免等核心知识点,以及合理使用线程池,对于编写高效、稳定的并发程序至关重要。通过实践,开发者可以更好地...

    java多线程_java多线程下变量共享_

    Java多线程是Java编程中的重要概念,它允许...理解并掌握Java多线程下变量共享的原理和解决方案,有助于编写出高效、稳定的并发程序。在实际开发中,应结合具体业务场景选择合适的同步机制,以达到最佳性能和安全性。

    Java多线程编程核心技术_完整版_java_

    Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程主要通过继承Thread类或实现Runnable接口来实现。本教程《Java多线程编程核心技术》将...

    汪文君JAVA多线程编程实战(完整不加密)

    此外,书中还深入探讨了线程安全问题,包括共享资源的并发访问、死锁、活锁、饥饿等问题,以及如何通过同步机制(如synchronized关键字、wait()、notify()和notifyAll()方法)来解决这些问题。Java内存模型(JMM)也...

    Java多线程技术精讲

    Java多线程技术是Java编程中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在现代计算机系统中,多线程是实现并发处理的关键技术,尤其在服务器端应用和高性能计算中不可或缺。 ...

    Java多线程练习题

    Java多线程是Java编程中的核心概念,它允许程序同时执行多个任务,提高了系统的效率和响应性。在Java中,多线程的实现主要通过两种方式:继承Thread类和实现Runnable接口。理解并掌握多线程的使用对于任何Java开发者...

    武汉理工大学Java多线程实验源码

    总结来说,这个实验源码涵盖了Java多线程的基础和应用,包括线程的创建、运行、同步、通信,以及网络编程和数据库操作。通过这些实验,学生可以深入理解Java并发编程的核心概念,并掌握实际开发中的多线程设计技巧。

    Java多线程编程实战指南-核心篇

    《Java多线程编程实战指南-核心篇》是一本深入探讨Java并发编程的书籍,旨在帮助读者掌握在Java环境中创建、管理和同步线程的核心技术。Java的多线程能力是其强大之处,使得开发者能够在同一时间执行多个任务,提高...

    java 多线程示例

    Java多线程是Java编程中的重要概念,尤其在开发高...通过`lec22`中的示例,你可以亲手实践这些概念,深入理解Java多线程的原理和应用。不断练习和探索,你将能够熟练地在实际项目中运用这些知识,提升你的编程技能。

    Java多线程编程

    Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程主要通过`Thread`类和并发工具来实现,接下来我们将深入探讨这些关键知识点。 1. **...

    java多线程实现生产者和消费者

    6. **死锁和饥饿**:在设计生产者-消费者模型时,需要注意避免死锁(两个或多个线程相互等待对方释放资源)和饥饿(某个线程因资源分配不当而永远无法执行)。例如,确保生产者不会无限等待消费者消费,消费者也不会...

    java多线程设计模式_java_设计模式_多线程_多线程课题_

    Java多线程设计模式是Java开发中的核心概念,它涉及到如何高效、安全地在多个执行线程之间共享资源和协调任务。设计模式是解决特定问题的成熟方案,它们是编程经验的结晶,可以帮助开发者在面临多线程挑战时快速找到...

    java 多线程课件

    Java多线程是Java编程中的一个重要概念,它允许程序同时执行多个任务,从而提高了程序的效率和响应速度。在Java中,多线程支持是语言级别的,这意味着开发者可以轻松地创建和管理并发执行的线程。 首先,我们要理解...

Global site tag (gtag.js) - Google Analytics