Java基础5(多线程)

多线程
一、概念
进程:进程是操作系统调度程序运行的基本单位,一个进程就是一个执行中的程序,永久介质上的一个程序的每一次运行都有一个进程对

象。操作系统以进程为单位分配相对独立的内存空间,包括代码空间、静态数据空间、动态堆、堆栈等,CPU资源的分配将按照一定的调

度策略进行。每一个进程的内部数据和状态几乎都是完全独立的。一般的,进程间的数据共享和交换是比较难的。

线程:线程是指进程中的更小的运行单位,彼此相对独立、可以重叠执行的独立的控制流。多线程则指的是在单个进程中可以同时运行多

个不同的线程,执行不同的任务。甚至是一个线程类的多个实例副本。属于一个进程的多个线程,其数据和代码空间事实上是处在同一个

进程地址空间中。不仅是可以方便共享内存和其他资源、实现通讯、降低调度负担,同时必须解决资源共享所带来的一系列冲突与同步问

题。由于多线程处于同一个进程之中,而且是各自独立的控制流,所以与进程相比,在创建、销毁、调度、相互通信等方面的开销远小于

进程,因此,线程被称为轻负荷进程(light-weight process)。

在Java虚拟机中看,虚拟机就是一个进程,而任何一个可运行的程序(main()方法)都是一个线程。

Java类库为程序员提供了两种建立线程的方式,一是继承线程基类Thread,一是实现线程接口Runnable,它们都在java.lang包中。
线程体:线程的核心在于它的控制流,因而在Thread和Runnable中对应的有一个最重要的方法run(),被称为线程体,它的执行过程就是

线程生命周期中的基本工作。

线程有5种状态:
1.已创建状态(new Thread)
执行下列语句创建一个线程对象时,线程就处于已创建状态:
Thread myThread = new MyThreadClass( );
这是线程进入已创建状态的必经过程。
当一个线程处于创建状态时,其控制流没有开始执行也不会开始执行,因而系统不为它分配CPU和堆栈资源。
2.可运行状态(Runnable)
执行下列语句后,使线程从已创建状态进入可运行状态,同时分配有关的资源如堆栈:
myThread.start( );
这是线程进入可运行状态的途径之一。
当一个线程处于可运行状态时,它就被安排在线程队列中等待调度。线程实际上并未占用CPU资源真正运行,但随时都可以被调度执行。
3.运行中状态(Running)
当系统为线程分配了CPU资源后的状态,此时线程的控制流真正在运行。
因为由于很多计算机都是单处理器的,所以要在同一时刻运行所有的处于可运行状态的线程是不可能的,Java的运行系统必须实现调度来

保证这些线程共享处理器。
4.不可运行状态(Not Runnable)或阻塞状态(Blocked)
当发生了某种事件后,运行中的线程暂时放弃CPU资源,进入到一种不能被调度执行的状态。
进入不可运行状态的原因有如下几条:
1) 自身调用了sleep()方法(休眠);
2) 自身调用了suspend()方法(挂起);
3) 为等候一个条件变量,线程自身调用wait()方法;
4) 输入输出流中发生线程阻塞;
不可运行状态也称为阻塞状态(Blocked)。因为某种原因(输入/输出、等待消息或其它阻塞情况),线程不能被系统执行的状态。这时

即使处理器空闲,也不能执行该线程。
5.死亡状态(Dead)
表示线程的生命周期结束后的状态。
线程的终止一般可通过两种途径实现:自然撤消(线程执行完)或是被停止(调用stop()方法)。目前不推荐通过调用stop()来终止线程

的执行,而是让线程执行完。


问题:
1、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?
有两种实现方法,分别使用new Thread()和new Thread(runnable)形式,第一种直接调用thread的run方法,所以,我们往往使用Thread

子类,即new SubThread()。第二种调用runnable的run方法。
有两种实现方法,分别是继承Thread类与实现Runnable接口
用synchronized关键字修饰同步方法
反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下

检查和修改它们。结果很难检查出真正的问题所在。suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然

持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢

复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志

,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重

新启动线程。

2、sleep() 和 wait() 有什么区别?
     sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢

复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(

或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

3、同步和异步有何异同,在什么情况下分别使用他们?举例说明。
如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数

据就是共享数据,必须进行同步存取。
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情

况下采用异步途径往往更有效率。

改变线程状态的方法:
1、线程的休眠sleep()
2、线程的暂停yield()
3、线程的连接join()
4、线程的中断interrupt()

线程通信方法:
(1)wait,nofity,notifyAll必须在已经持有锁的情况下执行,所以它们只能出现在synchronized作用的范围内,也就是出现在用synchronized

修饰的方法或类中。
(2) wait的作用:释放已持有的锁,进入等待队列(阻塞)。
(3) notify的作用:唤醒wait队列中的第一个线程并把它移入锁申请队列(可运行)。
(4) notifyAll的作用:唤醒wait队列中的所有的线程并把它们移入锁申请队列。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值