关于多线程的总结

来源:互联网 发布:淘宝美工兼职怎么收费 编辑:程序博客网 时间:2024/06/07 03:53


1、多线程的概念

线程是程序中一个单一的顺序控制流程。

在单个程序中同时运行多个线程完成不同的工作,称为多线程。

2、线程与进程

进程:是一个正在执行的程序,每一个执行都有一个执行顺序,该顺序是一个执行路径,或者叫叫一个控制单元。

线程:是进程中的一个独立的控制单元,线程在控制着进程执行。

一个进程至少有一个线程。

线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定线程的运行中需要使用计算机的内存资源和CPU

3、两种实现方式

第一种实现方式:继承Thread

1>实现步骤

a:定义类继承Thread

b:复写Thread类中的run方法

c:调用线程的start方法,方法有两个作用,一个是启动线程,另一个是调用run方法。

2>代码实现

//用继承Thread类方式实现多线程。  public class ThreadDemo{    public static void main(String arg[]){          T t1=new T();        T t2=new T();         //启动线程        t1.start();        t2.start();       }  }  class T extends Thread{ //继承Thread      //重写run()方法    public void run(){        System.out.println(this.getName());    }  } 


第二种实现方式:实现Runnable接口

1>实现步骤

a:定义类实现Runnable接口

b:覆盖Runnable接口的run方法

c:  通过Thread类建立线程对象

d:将runnable接口的子类对象作为实际对象,传递给Thread类的构造函数

e:  调用Thread类的start方法,开启线程调用Runnable接口子类的run方法。


2>代码实现

//用实现Runnable接口方式实现多线程。  public class ThreadDemo{  public static void main(String arg[]){        T t1=new T();      T t2=new T();      //通过Thread类建立线程对象,传递给THread类的构造函数    Thread th1=new Thread(t1);    Thread th2=new Thread(t2);    //启动线程      th1.start();      th2.start();     }  }  class T implements Runnable{ //实现Runnable接口    //覆盖run()方法  public void run(){      System.out.println(Thread.currentThread().getName());  }  


两种方式的区别:

a:实现Runnable接口的好处:避免了单继承的局限性

b: 继承Thread:线程代码存放在Thread子类的run方法中;

   实现Runnable接口:线程代码存放着接口子类的run方法中。


4、线程间的通信

线程间通信:

在一个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信

线程间通信的体现

一个线程传递数据给另一个线程;在一个线程中执行完特定任务后,转到另一个线程继续执行任务

等待唤醒机制:涉及的方法:

wait:将同步中的线程处于冻结状态。释放了执行权,释放了资格。同时将线程对象存储到线程池中。

notify:唤醒线程池中某一个等待线程。

notifyAll:唤醒的是线程池中的所有线程。

5、守护线程

守护线程是一类特殊的线程,它和普通线程的区别在于它并不是应用程序的核心部分 ,当一个应用程序的所有非守护线程终止运行时,即使仍然有守护线程在运行,应用程序 也将终止,反之,只要有一个非守护线程在运行,应用程序就不会终止。守护线程一般被 用于在后台为其它线程提供服务。  

可以通过调用方法 isDaemon() 来判断一个线程是否是守护线程,也可以调用方法 setDaemon() 来将一个线程设为守护线程。

 

6、如何停止线程

只用一种,run方法结束。

开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,即线程结束。

特殊情况:当线程处于冻结状态,就不会读取到标记,那么线程就不会结束,这时需要对冻结进行清除,强制让线程恢复运行状态中。

 

7、线程池

诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务。 服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的。 

构建服务器应用程序的一个过于简单的模型应该是:每当一个请求到达就创建一个新线程,然后在新线程中为请求服务。

那么这种方法的严重不足就很明显。每个请求对应一个线程(thread-per-request)方法的不足之一是:为每个请求创建一个新线程的开销很大 ;在一个 JVM 里创建太多的线程可能会导致系统由于过度消耗内存而用完内存或“切换过度”。为了防止资源不足,服务器应用程序需要一些办法来限制任何给定时刻处理的请求数目。 

我们可以实现一个线程池类,其中客户机类等待一个可用线程、将任务传递给该线程以便执行、然后在任务完成时将线程归还给池, 

一般一个简单线程池至少包含下列组成部分: 

a.线程池管理器(ThreadPoolManager:用于创建并管理线程池 u 

b.工作线程(WorkThread线程池中线程 

c.任务接口(Task:每个任务必须实现的接口,以供工作线程调度任务的执行。 u 

d.任务队列:用于存放没有处理的任务。提供一种缓冲机制

 

8、线程的调度

线程调度是指按照特定机制为多个线程分配CPU的使用权.

有两种调度模型:分时调度模型和抢占式调度模型。

分时调度模型是指让所有的线程轮流获得cpu的使用权,并且平均分配每个线程占用的CPU的时间片这个也比较好理解。

java虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。 处于运行状态的线程会一直运行,直至它不得不放弃CPU

一个线程会因为以下原因而放弃CPU

1)java虚拟机让当前线程暂时放弃CPU,转到就绪状态,使其它线程获得运行机 会。

2)当前线程因为某些原因而进入阻塞状态

3) 线程结束运行

需要注意的是,线程的调度不是跨平台的,它不仅仅取决于java虚拟机,还依赖于操作系统。在某些操作系统中,只要运行中的线程没有遇到阻塞,就不会放弃CPU;在某些操作系统中,即使线程没有遇到阻塞,也会运行一段时间后放弃CPU,给其它线程运行的机会。

java的线程调度是不分时的,同时启动多个线程后,不能保证各个线程轮流获得均等的CPU时间片。

如果希望明确地让一个线程给另外一个线程运行的机会,可以采取以下办法之一。

调整各个线程的优先级

让处于运行状态的线程调用Thread.sleep()方法

让处于运行状态的线程调用Thread.yield()方法

让处于运行状态的线程调用另一个线程的join()方法

线程切换:不是所有的线程切换都需要进入内核模式

 

 

 

 

 

 

 

 

 

 

0 0
原创粉丝点击