疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java中的多线程


 

  一、 java线程基本介绍

  1、进程与线程的区别

  进程是指一个内存中运行的应用程序,每个进程都有一块独立的内存空间,一个进程包含一到多个线程。

  每个线程都有他所属的进程,每个线程也就是该进程的一条执行路径,线程之间是高频率快速轮换执行的,‘同时’执行只是给人的感觉。

  2、Java当中线程一般有5中状态

  创建状态:生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。

  就绪状态:当调用了线程的start方法,线程就进入就绪状态,调用start方法后线程不是立即执行的,只是开始排队等待执行了,具体什么时候执行得看CPU心情,当线程从等待或者休眠状态回来之后也是进入到就绪状态。

  运行状态:开始运行run()函数的代码,这时候就是运行状态啦。

  阻塞状态:线程正在运行的时候被暂停就是进入到阻塞状态,sleep,suspend,wait都可以使线程进入阻塞状态。

  死亡状态:run()方法运行结束或者调用了线程的stop方法后,该线程就会死亡,对于已经死亡的线程无法使用start方法使其进入就绪状态。

  在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。

  先看一个简单的例子:

  复制代码

  1 package com.hxw.Threads;

  2 class ThreadTest {

  3 /**

  4 * 观察直接调用run()和用start()启动一个线程的差别

  5 * @author HaiCheng

  6 * @param args

  7 * @throws Exception

  8 */

  9 public static void main(String[] args){

  10 Threadr=new ThreadDemo("直接调用run执行");

  11 r.run();

  12 Thread t1=new ThreadDemo("线程一");

  13 t1.start();

  14 Thread t2=new ThreadDemo("线程二");

  15 t2.start();

  16 for(int i=0;i<10;i++){

  17 System.out.println("主线程执行------>"+i);

  18 }

  19 }

  20 public static class ThreadDemo extends Thread{

  21 private String ThreadName;

  22 public ThreadDemo(String s){

  23 this.ThreadName=s;

  24 }

  25 @Override

  26 public void run() {

  27 for (int i = 0; i < 10; i++) {

  28 System.out.println(this.getThreadName()+"执行------>"+i);

  29 }

  30 }

  31 public String getThreadName() {

  32 return ThreadName;

  33 }

  34 }

  35 }

  复制代码

  run和start的区别

  1) start:

  用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到spu时间片,就开始执行run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。

  2) run:

  run方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。

  总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。

 

  class 类名 extends Thread{

  方法1;

  方法2;

  …

  public void run(){

  // other code…

  }

  属性1;

  属性2;

  …

  }

  通过实现Runnable接口:

  大致框架是:

  class 类名 implements Runnable{

  方法1;

  方法2;

  …

  public void run(){

  // other code…

  }

  属性1;

  属性2;

  …

  }

  来先看一个小例子吧:

  /**

  * @author Rollen-Holt 实现Runnable接口

  * */

  class hello implements Runnable {

  public hello() {

  }

  public hello(String name){

  this.name= name;

  }

  public void run() {

  for (int i= 0; i < 5; i++) {

  System.out.println(name+ "运行 " + i);

  }

  }

  public static void main(String[]args) {

  helloh1=new hello("线程A");

  Threaddemo= new Thread(h1);

  helloh2=new hello("线程B");

  Threaddemo1=new Thread(h2);

  demo.start();

  demo1.start();

  }

  private Stringname;

  }

  【可能的运行结果】:

  线程A运行 0

  线程B运行 0

  线程B运行 1

  线程B运行 2

  线程B运行 3

  线程B运行 4

  线程A运行 1

  线程A运行 2

  线程A运行 3

  线程A运行 4

  关于选择继承Thread还是实现Runnable接口?

  其实Thread也是实现Runnable接口的:

  Thread和Runnable的区别:

  如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

 

  /**

  * @author Rollen-Holt 继承Thread类,不能资源共享

  * */

  class hello extends Thread {

  public void run() {

  for (int i= 0; i < 7; i++) {

  if (count> 0) {

  System.out.println("count=" + count--);

  }

  }

  }

  public static void main(String[]args) {

  helloh1 = new hello();

  helloh2 = new hello();

  helloh3 = new hello();

  h1.start();

  h2.start();

  h3.start();

  }

  private int count =5;

  }

  【运行结果】:

  count= 5

  count= 4

  count= 3

  count= 2

  count= 1

  count= 5

  count= 4

  count= 3

  count= 2

  count= 1

  count= 5

  count= 4

  count= 3

  count= 2

  count= 1

  大家可以想象,如果这个是一个买票系统的话,如果count表示的是车票的数量的话,说明并没有实现资源的共享。

  我们换为Runnable接口

  复制代码

  class MyThread implements Runnable{

  private int ticket =5; //5张票

  public void run() {

  for (int i=0;i<=20; i++) {

  if (this.ticket> 0) {

  System.out.println(Thread.currentThread().getName()+"正在卖票"+this.ticket--);

  }

  }

  }

  }

  public class lzwCode {

  public static void main(String[] args) {

  MyThreadmy = new MyThread();

  new Thread(my,"1号窗口").start();

  new Thread(my,"2号窗口").start();

  new Thread(my,"3号窗口").start();

  }

  }

  复制代码

  【运行结果】:

  count= 5

  count= 4

  count= 3

  count= 2

  count= 1

  总结一下吧:

  实现Runnable接口比继承Thread类所具有的优势:

  1):适合多个相同的程序代码的线程去处理同一个资源

  2):可以避免java中的单继承的限制

  3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。