线程是Java的一大特性,它可以是给定的指令序列、给定的方法中定义的变量或者一些共享数据(类一级的变量)。在Java中每个线程有自己的堆栈和程序 计数器(PC),其中堆栈是用来跟踪线程的上下文(上下文是当线程执行到某处时,当前的局部变量的值),而程序计数器则用来跟踪当前线程正在执行的指令。
在通常情况下,一个线程不能访问另外一个线程的堆栈变量,而且这个线程必须处于如下状态之一:
1.排队状态 (Ready),在用户创建了一个线程以后,这个线程不会立即运行。当线程中的方法start()被调用时,这个线程就会进行排队状态,等待调度程序将它 转入运行状态(Running)。当一个进程被执行后它也可以进行排队状态。如果调度程序允许的话,通过调用方法yield()就可以将进程放入排队状 态。
2.运行状态(Running),当调度程序将CPU的运行时间分配给一个线程,这个线程就进入了运行状态开始运行。
3.等待状态(Waiting),很多原因都可以导致线程处于等待状态,例如线程执行过程中被暂停,或者是等待I/O请求的完成而进入等待状态。
在Java 中不同的线程具有不同的优先级,高优先级的线程可以安排在低优先级线程之前完成。如果多个线程具有相同的优先级,Java会在不同的线程之间切换运行。一 个应用程序可以通过使用线程中的方法setPriority()来设置线程的优先级,使用方法getPriority()来获得一个线程的优先级。
线程的生命周期
一 个线程的的生命周期可以分成两阶段:生存(Alive)周期和死亡(Dead)周期,其中生存周期又包括运行状态(Running)和等待状态 (Waiting)。当创建一个新线程后,这个线程就进入了排队状态(Ready),当线程中的方法start()被调用时,线程就进入生存周期,这时它 的方法isAlive()始终返回真值,直至线程进入死亡状态。
线程的实现
有两种方法可以实现线程,一种是扩展java.lang.Thread类,另一种是通过java.lang.Runnable接口。
Thread 类封装了线程的行为。要创建一个线程,必须创建一个从Thread类扩展出的新类。由于在Thread类中方法run()没有提供任何的操作,因此,在创 建线程时用户必须覆盖方法run()来完成有用的工作。当线程中的方法start()被调用时,方法run()再被调用。下面的代码就是通过扩展 Thread类来实现线程:
java 代码
- import
java.awt.*;
- class
Sample1{
- public
static
void
main(String[] args){
- Mythread test1=new
Mythread(
1
);
- Mythread test2=new
Mythread(
2
);
- test1.start();
- test2.start();
- }
- }
-
- class
Mythread
extends
Thread {
- int
id;
- Mythread(int
i)
- { id=i;}
- public
void
run() {
- int
i=
0
;
- while
(id+i==
1
){
- try
{sleep(
1000
);
- } catch
(InterruptedException e) {}
- }
- System.out.println(“The id is ”+id);
- }
通 常当用户希望一个类能运行在自己的线程中,同时也扩展其它某些类的特性时,就需要借助运行Runnable接口来实现。Runnable接口只有一个方法 run()。不论什么时候创建了一个使用Runnable接口的类,都必须在类中编写run()方法来覆盖接口中的run()方法。例如下面的代码就是通 过Runnable接口实现的线程:
java 代码
- import
java.awt.*;
- import
java.applet.Applet;
- public
class
Bounce
extends
Applet
implements
Runnable{
- static
int
r=
30
;
- static
int
x=
100
;
- static
int
y=
30
;
- Thread t;
- public
void
init()
- {
- t = new
Thread(
this
);
- t.start();
- }
- public
void
run()
- {
- int
y1=+
1
;
- int
i=
1
;
- int
sleeptime=
10
;
- while
(
true
)
- {
- y+=(i*y);
- if
(y-rgetSize().height)
- y1*=-1
;
- try
{
- t.sleep(sleeptime);
- }catch
(InterruptedException e){ }
- }
- }
- }
为什么要使用线程池
在Java 中,如果每当一个请求到达就创建一个新线程,开销是相当大的。在实际使用中,每个请求创建新线程的服务器在创建和销毁线程上花费的时间和消耗的系统资源, 甚至可能要比花在处理实际的用户请求的时间和资源要多得多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个JVM里创建太多的 线程,可能会导致系统由于过度消耗内存或“切换过度”而导致系统资源不足。为了防止资源不足,服务器应用程序需要一些办法来限制任何给定时刻处理的请求数 目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务,这就是“池化资源”技术产生的原因。
线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在 请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。另外,通过适当地调整线程池中的线程数目可 以防止出现资源不足的情况。
创建一个线程池
一个比较简单的线程池至少应包含线程池管理器、工作线 程、任务队列、任务接口等部分。其中线程池管理器(ThreadPool Manager)的作用是创建、销毁并管理线程池,将工作线程放入线程池中;工作线程是一个可以循环执行任务的线程,在没有任务时进行等待;任务队列的作 用是提供一种缓冲机制,将没有处理的任务放在任务队列中;任务接口是每个任务必须实现的接口,主要用来规定任务的入口、任务执行完后的收尾工作、任务的执 行状态等,工作线程通过该接口调度任务的执行。下面的代码实现了创建一个线程池,以及从线程池中取出线程的操作:
java 代码
- public
class
ThreadPool
- {
- private
Stack threadpool =
new
Stack();
- private
int
poolSize;
- private
int
currSize=
0
;
- public
void
setSize(
int
n)
- {
- poolSize = n;
- }
- public
void
run()
- {
- for
(
int
i=
0
;i
- {
- WorkThread workthread=new
WorkThread();
- threadpool.push(workthread);
- currSize++;
- }
- }
- public
synchronized
WorkThread getworker( )
- {
- if
(threadpool.empty())
- system.out.println(“stack is empty”);
- else
- try
{
return
threadpool.pop();
- } catch
(EmptyStackException e){}
- }
- }
线程池适合应用的场合
当 一个Web服务器接受到大量短小线程的请求时,使用线程池技术是非常合适的,它可以大大减少线程的创建和销毁次数,提高服务器的工作效率。但如果线程要求 的运行时间比较长,此时线程的运行时间比创建时间要长得多,单靠减少创建时间对系统效率的提高不明显,此时就不适合应用线程池技术,需要借助其它的技术来 提高服务器的服务效率。
分享到:
相关推荐
Java中Executors类中几种创建各类型线程池方法及简单实例
线程池是一种多线程处理形式,预先创建了若干个线程,当有任务需要执行时,会从线程池中取出一个线程来执行任务,任务执行完毕后,线程返回线程池中等待新的任务。这种机制避免了频繁创建和销毁线程带来的性能开销,...
`ConsumeThreadPoolPara` 是一个 JavaBean,用于存储线程池的参数,包括最小和最大线程数、检查线程池中线程的周期等参数。该类实现了 Serializable 接口,用于序列化和反序列化。 三、解析 xml 程序代码 使用 ...
2. **工作线程(Worker Threads)**:线程池中的线程,用于执行提交的任务。它们在没有任务时会等待,而不是立即销毁,这样可以避免频繁创建和销毁线程的开销。 3. **任务队列(Task Queue)**:一个队列用来存储待...
因为线程池中仍然有很多线程在运行,占用系统资源,导致内存泄露和应用崩溃。 通过实例代码,我们可以看到,如果不关闭线程池,可能会导致内存泄露和应用崩溃。在代码中,我们创建了一个线程池,然后执行一个打印...
- 线程池中的线程如果在执行过程中遇到未捕获的异常,线程池默认会记录这个异常并终止该线程。 通过深入研究和使用本资源提供的"JAVA经典线程池源码",开发者不仅可以理解线程池的基本工作原理,还能学习到如何...
目标:Java中多线程技术是一个难点,但是也是一个核心技术。因为Java本身就是一个多线程语言。本人目前在给46班讲授Swing的网络编程--使用Swing来模拟真实的QQ实时聊天软件。因为涉及到Socket编程,所以一定会使用多...
PooledThread类继承自Thread类,用于实现线程池中的线程,PooledThread类提供了多个方法来管理线程池中的线程,例如putTask、putTasks、stopTasks、pauseTasks等方法;ThreadPool类用于管理线程池中的线程,提供了多...
3. 当线程池中的线程数量大于核心线程数且小于最大线程数时,新任务会创建线程执行,同时将超出核心线程数的线程设置为非核心线程。 4. 当线程池线程数达到最大值并且工作队列已满,将根据拒绝策略处理新任务。 ###...
Java线程池是一种高效管理并发任务执行的机制,它通过预先创建并维护一定数量的线程,从而避免了频繁地创建和销毁线程所带来的性能开销。在Java中,线程池的实现主要依赖于`java.util.concurrent`包中的`...
此时,如果没有空闲线程来执行任务A,那么线程池中的所有工作线程都将永久阻塞,形成死锁。 为了避免这类问题,需要仔细设计线程池的使用场景。例如,不要将需要等待其他任务执行结果的任务放入线程池的工作队列中...
Java8并行流中自定义线程池操作示例 Java8并行流中自定义线程池操作示例主要介绍了Java8并行流中自定义线程池操作,结合实例形式分析了并行流的相关概念、定义及自定义线程池的相关操作技巧。 1. 概览 Java8引入了...
### 自定义实现Java线程池 #### 一、概述 在深入探讨自定义Java线程池之前,我们先简要回顾一下线程池的基本概念及其重要性。线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动...
Java线程池是Java并发编程中的重要组件,它能够有效地管理和复用线程,从而提高程序的执行效率和降低资源消耗。在JDK 1.5版本之前,Java对线程池的支持非常有限,而在JDK 1.5之后,加入了java.util.concurrent包,...
- **资源复用**: 线程池中的线程可以被重复使用,减少了创建和销毁线程的开销。 - **任务调度**: 可以设置不同的拒绝策略,如抛弃任务、抛出异常或调用用户自定义处理方式。 - **控制并发**: 通过设置线程池参数,...
Java线程池是Java并发编程中的重要组成部分,它在多线程和高并发场景下扮演着关键角色。本文将深入探讨Java线程池的源码分析,并对比不同类型的线程池,以帮助开发者更好地理解和利用这一强大的工具。 首先,我们要...
线程池是一种线程使用模式,它预先创建了一组可重用的线程,当有任务需要执行时,不再直接创建新的线程,而是从线程池中取出一个空闲线程来执行任务,完成任务后线程返回到线程池而不是直接销毁。这样可以避免频繁地...
线程池是由多个工作线程组成的集合,它可以预先创建一定数量的线程,当有任务需要执行时,从池中取出一个线程来执行任务,任务完成后,线程不立即销毁,而是返回到线程池中等待下一个任务。这种方式避免了频繁创建和...
2. 工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务。 3. 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的...
Java线程池是一种高效管理线程资源的工具,它能够帮助开发者有效地控制并调度线程,从而提升系统性能,减少系统资源的浪费。在Java中,`ExecutorService`接口是线程池的主要入口,它是`java.util.concurrent`包的一...