`
student_lp
  • 浏览: 428073 次
  • 性别: 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多线程编程的优点和缺点

    死锁(Deadlocks):多线程编程容易出现死锁,即多个线程相互等待对方释放资源的情况,导致程序无法继续执行。 线程同步开销:线程同步机制引入了额外的开销,如锁竞争、上下文切换等,可能降低程序性能

    java多线程安全性基础介绍.pptx

    java多线程安全性基础介绍 线程安全 正确性 什么是线程安全性 原子性 竞态条件 i++ 读i ++ 值写回i 可见性 JMM 由于cpu和内存加载速度的差距,在两者之间增加了多级缓存导致,内存并不能直接对cpu可见。 ...

    JAVA多线程 竞态条件、死锁及同步机制.docx

    线程之间共享堆空间,在编程的时候就要格外注意避免竞态...危险在于 多个线程同时访问相同的资源并进行读写操作 。当其中一个线程需要根据某个变量的状态来相应执行某个操作的之前,该变量很可能已经被其它线程修改。

    基于多线程的电梯调度模拟仿真系统 开题报告

    Java的多线程机制能够很方便地创建和运行多个独立的线程的程序,并且可以创建多个同步线程,实现多个任务的同步执行,这一机制对于实现资源共享、防止“死锁”现象的出现极为有用。多线程的程序能更好地表达和解决具体...

    Java高级程序设计-多线程(二).pptx

    线程的创建有继承Thread类和实现Runnable接口两种方式,通过Runnable方式可以更加容易实现多线程之间资源共享。 通过sleep可以使线程进入休眠状态,通过join方法可以让线程处于等待,其他线程执行完毕后继续执行。 ...

    多线程操作实例源码,,

    浏览器就是一个很好的多线程的例子,在浏览器中你可以在下载JAVA小应用程序或图象的同时滚动页面,在访问新页面时,播放动画和声音,打印文件等。  多线程的好处在于可以提高CPU的利用率——任何一个程序员都不希望...

    多线程操作实例源码

    浏览器就是一个很好的多线程的例子,在浏览器中你可以在下载JAVA小应用程序或图象的同时滚动页面,在访问新页面时,播放动画和声音,打印文件等。  多线程的好处在于可以提高CPU的利用率——任何一个程序员都不希望...

    JAVA 多线程

    线程也可以达到同一份程序产生好几个进程的效果,但是不同的线程之间可以有某种程度上的资源共享,所以线程又被称为轻量级进程(lightweight process)。  Threads run at the same time, independently of one ...

    什么是死锁,如何避免死锁?Java死锁详解

    举例:假如有线程Thread1和Thread2,两个都要访问共享资源AB,Thread1和Thread2一个先访问A再访问B,另一个先访问B再访问A。但在他们线程未执行完时,都不会释放AB资源,那么就形成了一种僵局,Thread1在等待Thead2...

    java并发编程理论基础精讲

    本资源为您提供了关于 Java 并发编程理论基础的精讲,涵盖了多线程编程的核心概念、基本原理以及在 Java 中的应用。通过深入学习,您将建立坚实的并发编程基础,能够更好地理解和应对多线程编程中的挑战。 并发编程...

    死锁_Java产生死锁的简单案例

    多个线程各自占有一些共享资源,并且互相等待其它线程占有的资源才能进行,而导致的两个或多个线程都在等待对方释放资源,都停止执行的情景。某一个同步块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”的...

    JAVA实现Modbus RTU或Modbus TCPIP数据采集.rar

    2.多线程之间为更方便的实现数据共享采用了共享相同内存地址空间的形式,并且是并发运行,导致多个线程可能会同时访问或修改其他线程正在使用的变量值,导致安全性,同时如果线程之间相互等待对方拥有的锁,会出现...

    JAVA 范例大全 光盘 资源

    JAVA 范例大全 光盘 资源 书籍目录: 前言. 第1章 开发环境搭建 1 实例1 下载、安装并配置JDK 1 实例2 第一个Java程序 3 实例3 在Eclipse中创建第一个Java程序 4 常见问题 javac不是内部或者外部命令 6 常见...

    JAVA上百实例源码以及开源项目

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

    JAVA上百实例源码以及开源项目源代码

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

    校招应用软件开发工程师(Java)

    2、关于进程和线程描述正确的是(C) A、进程是CPU调度的最小单位 B、线程是最小的资源分配单位 C、一个线程只能属于一个进程 D、同一进程中的多个线程不能并发执行; 11、关于数据库中的锁的说法,错误的是() A、...

    java笔试题大集合及答案(另附各大公司笔试题)

    60、java中有几种方法可以实现一...答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口 同步的实现方面有两种,分别是synchronized,wait与notify 67、线程的基本概念、线程的基本状态以及状态之间的关系

    java 编程入门思考

    14.2.2 Java如何共享资源 14.2.3 回顾Java Beans 14.3 堵塞 14.3.1 为何会堵塞 14.3.2 死锁 14.4 优先级 14.4.1 线程组 14.5 回顾runnable 14.5.1 过多的线程 14.6 总结 14.7 练习 第15章 网络编程 15.1 机器的标识...

    Java初学者入门教学

    14.2.2 Java如何共享资源 14.2.3 回顾Java Beans 14.3 堵塞 14.3.1 为何会堵塞 14.3.2 死锁 14.4 优先级 14.4.1 线程组 14.5 回顾runnable 14.5.1 过多的线程 14.6 总结 14.7 练习 第15章 网络编程 15.1 机器的标识...

Global site tag (gtag.js) - Google Analytics