浅谈多线程

来源:互联网 发布:webuploader php 编辑:程序博客网 时间:2024/06/06 05:23

在Java语言中,同一个程序内部的并发处理由线程这个概念来实现。

 

1.      程序与进程

      程序:一段静态的代码

 

    进程:程序的一次动态执行过程,它对应从代码加载、执行到执行完毕的一个完整过程。

进程也称任务,支持多个进程同时执行的操作系统就被称为多进程操作系统或多任务操作系统

2.      进程与线程。

   在一个程序内部也可以实现多个任务并发执行,其中每个任务称为线程。线程是比进程更小的执行单位,它是在一个进程中独立的控制流,即程序内部的控制流。

 

 特点:

线程不能独立运行,必须依赖于进程,在进程中运行。

每个程序至少有一个线程称为主线程

单线程:只有一条线程的进程称为单线程

多线程:有不止一个线程的进程称为多线程

 

3.      开启多线程的优点和缺点

    提高界面程序响应速度。

    充分利用系统资源,提高效率。

   当程序中的线程数量比较多时,系统将花费大量的时间进行线程的切换,这反而会降低程序的执行效率。但是,相对于优势来说,劣势还是很有限的,所以现在的项目开发中,多线程编程技术得到了广泛的应用。

 

 

在实现线程编程时,首先需要让一个类具备多线程的能力,继承Thread类或实现Runnable接口的类具备多线程的能力,然后创建线程对象,调用对应的启动线程方法即可实现线程编程。

    在一个程序中可以实现多个线程,多线程编程指在同一个程序中启动了两个或两个以上的线程。

 

4.      多线程的实现途径

    Java语言提供了三种实现方式:

ü      继承Thread类

ü      实现Runnable接口

ü      使用Timer和TimerTask组合

但常用的是前两种

 

a)       继承Thread线程类实现多线程

 

   java.lang包中提供了一个专门的线程类(Thread),在该类中封装了许多对线程进行调度和处理的方法。如果一个类继承了Thread类,则该类就具备了多线程的能力,可以多线程的方式执行。

 

如:

     //继承Thread类

   class   MyThread extends Thread{

 

        //重写run()方法

       public void run(){

                //线程体

        }

  Publicstatic void main(String [] arg s) {
  MyThread  tt1 = new MyThread (); //创建线程对象

 

  //启动线程

  tt1.start();//调用线程对象start()启动线程

 

  try{

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

          //延时1秒

          Thread.sleep(1000);

          System.out.println("Main:"+ i);

   }

  }catch(Exceptione){}

 

}

   }

 

注意:

线程的特性:随机性,系统在执行多线程程序时只保证线程是交替执行的,至于哪个线程先执行哪个线程后执行,则无法获得保证,需要书写专门的代码才可以保证执行的顺序。

对于同一个线程类,也可以启动多个线程。
Thread2 t2 = new Thread2();   t2.start();
Thread2 t3 = new Thread2();   t3.start();

同一个线程不能启动两次,例如 
Thread2 t2 = new Thread2();
t2.start();          t2.start();   //错误

 当自定义线程中的run方法执行完成以后,则自定义线程自然死亡。而对于系统线程来说,只有当main方法执行结束,而且启动的其它线程都结束以后,才会结束。当系统线程执行结束以后,程序的执行才真正结束。

 

b) 实现Runable接口

       多线程对象实现java.lang.Runnable接口并且在该类中重写Runnable接口的run方法。

好处:实现Runable接口的方法避免了单继承的局限性。

   

   如:

    publicclass TestThread1 {

 

 

    publicstaticvoid main(String[] args) {

       //TODO Auto-generatedmethod stub

       TestThread1 tt1 = new TestThread1();

        Thread1 td1 =tt1.new Thread1("td1");

          Thread1 td2 =tt1.new Thread1("td2");

          Thread t1 =new Thread(td1);

   

          t1.start();

          Thread t2 =new Thread(td2);

      

          t2.start();

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

          System.out.println("main..."+i);

          }

    }

    class Thread1implements Runnable{

       private Stringname;

       Thread1(String name){

           this.name = name;

       }

       @Override

       publicvoid run() {

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

              try {

                  Thread.sleep(1000);

                  System.out.println(Thread.currentThread().getName()+"....."+i);

              } catch (InterruptedException e) {

                  //TODO Auto-generatedcatch block

                  e.printStackTrace();

              }

             

       }

          

       }

 

}

}

 接口编程步骤:

1.实现java.lang.Runnable接口;

2.重写Runnable接口的run方法;

3.创建Runnable接口的子类对象;

4.创建Thread类的对象,并将Runnable接口的子类对象作为参数传递给Thread类的构造方法,最后调用Thread对象的start方法即可启动线程。

     Runnable1 r1 = newRunnable1();

     Thread t1 = newThread(r1);

     t1.start();

 

  5. 线程的生命周期

 线程是一个动态执行的过程,它也有一个从产生到死亡的过程,这就是所谓的生命周期。一个线程在它的生命周期内有5种状态:

新建、就绪、运行、死亡、堵塞

 

新建

当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread  t1=new Thread();

 

就绪
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();

 

运行
线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

 

 死亡
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。

ü       自然终止:正常运行run()方法后终止

ü       异常终止:调用stop()方法让一个线程终止运行

           

        堵塞
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。

ü       正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。

ü       正在等待:调用wait()方法。(调用notify()方法回到就绪状态)

ü       被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)

 

 

   6. 线程的优先级

线程从就绪状态进入运行状态的过程叫做线程调度

负责调度工作的机构叫做调度管理器

优先级:线程的优先级的取值范围是1~10。
MAX_PRIORITY    =    10
NORM_PRIORITY   =   5
MIN_PRIORITY    =    1

得到或修改线程的优先级
public final int getPriority();
public final void setPriority(int newPriority);

 

void run()   //创建该类的子类时必须实现的方法

void start() //开启线程的方法

static void sleep(long t) //释放CPU的执行权,不释放锁

static void sleep(long millis,int nanos)

final void wait()//释放CPU的执行权,释放锁

final void notify()

static void yied()//可以对当前线程进行临时暂停(让线程将资源释放出来)

public final void stop()//结束线程,但由于安全的原因过时

 

 

注意:结束线程原理---就是让run方法结束。而run方法中通常会定义循环结构,所以只要控制住循环即可。

方法----可以boolean标记的形式完成,只要在某一情况下将标记改变,让循环停止即可让线程结束。但是,特殊情况,线程在运行过程中,处于了冻结状态,是不可能读取标记的。

那么这时,可以通过正常方式恢复到可运行状态,也可以强制让线程恢复到可运行状态,通过Thread类中的,interrupt():清除线程的冻结状态,但这种强制清除会发生InterruptedException。所以在使用 wait,sleep,join方法的时候都需要进行异常处理。

 

interrupt()方法:中断线程

但实际上该方法不会中断正在执行的线程,只是将线程的标志位设置成true(可以用isInterrupted()方法测试该线程的中断标记,并不清除中断标记,static的方法interrupted()测试当前执行的线程是否被中断,并且在肯定的情况下,清除当前线程对象的中断标记并返回true)

如果线程在调用sleep(),join(),wait()方法时线程被中断,则这些方法会抛出InterruptedException,在catch块中捕获到这个异常时,线程的中断标志位已经被设置成false了 。

 

public final void join()//让线程加入执行,执行某一线程join方法的线程会被冻结,等待某一线程执行结束,该线程才会恢复到可运行状态

public final boolean isAlive()                /’diːmən /

将线程标记为守护线程(后台线程):setDaemon(true); 注意该方法要在线程开启前使用。和前台线程一样开启,并抢资源运行,所不同的是,当前台线程都结束后,后台线程会自动结束。无论后台线程处于什么状态都会自动结束。

 

实例:

设置线程优先级

 

package com.hbsi;

publicclass SetPriority { 

    publicstaticvoid main(String[] args) {

       MyThread threadA= new MyThread("threadA", 8);  

       threadA.start();   

       MyThread threadB= new MyThread("threadB", 2);  

       threadB.start();

       MyThread threadC= new MyThread("threadC", 7);  

       threadC.start();

       try {

           Thread.sleep(3000);

       }catch (InterruptedException x) {

       }

       threadA.setPriority(3);

       System.out.println("in main() -threadA.getPriority()=" +threadA.getPriority());

       }

}

class MyThreadextends Thread{

    public MyThread(String name,int i){

       setPriority(i);

       setName(name);

    }  

    publicvoid run() {

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

           System.out.println("priority=" + getPriority() +", name=" + getName());

           try {

              Thread.sleep(2000);

           }catch (InterruptedException x) {

           }

       }

    }

}

 

测试join方法

 

package csdn.java.thread;

 

publicclass TestJoin {

 

    /**

     * @param args

     */

    publicstaticvoid main(String[] args) {

 

   

        

           Thread td1 = new ThreadDemo("td1");

           ThreadDemo td2 = new ThreadDemo("td2");

          

           td1.start();

           try {

              td1.join();

           } catch (InterruptedException e) {

              //TODO Auto-generatedcatch block

              e.printStackTrace();

           }

          

           td2.start();

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

      

              System.out.println("main..."+i);

 

       }

 

   

 

}

}

class ThreadDemoextends Thread{

 

    private Stringname;

    ThreadDemo(String name){

       this.name = name;

    }

    publicvoid run() {

      

       super.run();

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

      

           System.out.println(Thread.currentThread().getName()+name+"..."+i);

       }

       }

   }

 测试yield方法

   

package csdn.java.thread;

 

import java.util.Date;

 

publicclass TestYield {

 

    /**

     * @param args

     */

    publicstaticvoid main(String[] args) {

 

        Yield y1 = new Yield(false);

        Yield y2 = new Yield(true);

        Yield y3 = new Yield(false);

        

        y1.start();

        y2.start();

        y3.start();

 

    }

 

}

class Yieldextends Thread{

    privatebooleanflag =true;

   

    public Yield(boolean flag){

       this.flag = flag;

    }

    publicvoid run(){

       long start =new Date().getTime();

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

           if(flag ){

           Thread.yield();

          

          

       }

              for(int j=0;j<2000;j++){

              ;

           }

             

           }

       long end =new Date().getTime();

       System.out.println(Thread.currentThread().getName()+"..."+(start-end)+"毫秒");

   

      

    }

}

 

一个程序测试线程的生命周期

   importjava.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import java.awt.*;

 

public class TestStatus extends WindowAdapter implementsActionListener{

 

     /**

      * @param args

      */

    

     Frame f;

     staticTestStatus.ThreadTest t1,t2;

     public static voidmain(String[] args) {

            TestStatus w=newTestStatus();

            w.display();

            t1=w.newThreadTest("Welecome to Java world!");

            t2=w.newThreadTest("Welecome to Study thread!");

            t2.start();

            t2.setButton();

           

           

           

 

     }

     public void display(){

            f=newFrame("welcome");

            f.setSize(200,200);

            f.setLocation(200,140);

            f.setBackground(Color.lightGray);

            f.setLayout(newGridLayout(4,1));

            f.addWindowListener(this);

            //f.setVisible(true);

     }

 

     @Override

     public voidactionPerformed(ActionEvent e) {

            // TODOAuto-generated method stub

            if((e.getSource()==t1.b1)||(e.getSource()==t1.b2))

                   actionPerformed(e,t1);

            if((e.getSource()==t2.b1)||(e.getSource()==t2.b2))

                   actionPerformed(e,t2);

     }

    

     public voidactionPerformed(ActionEvent e,ThreadTest t){

            if(e.getSource()==t.b1){

                   t.sleeptime=Integer.parseInt(t.tf2.getText());

                   t.start();

            }

            if(e.getSource()==t.b2)

                   t.interrupt();

            t.setButton();

     }

    

     public class ThreadTestextends Thread{

            Panel p1;

            Label lb1;

            TextField tf1,tf2;

            Button b1,b2;

            intsleeptime=(int)(Math.random()*100);

            publicThreadTest(String str){

                   super(str);

                   for(inti=0;i<100;i++){

                          str=str+"";

                         

                   }

                  

                   tf1=newTextField(str);

                   f.add(tf1);

                   p1=newPanel();

                   p1.setLayout(newFlowLayout(FlowLayout.LEFT));

                   lb1=newLabel("sleep");

                   tf2=new TextField(""+sleeptime);

                   p1.add(lb1);

                   p1.add(tf2);

                   b1=newButton("启动");

                   b2=newButton("中断");

                   p1.add(b1);

                   p1.add(b2);

                   b1.addActionListener(newTestStatus());

                   b2.addActionListener(newTestStatus());

                  

                   f.add(p1);

                   f.setVisible(true);

           

            }

            public void run(){

                   String str;

                   //while(this.isAlive()&&!this.isInterrupted()){

                   while(true){

                          try{

                                 str=tf1.getText();

                                 str=str.substring(1)+str.substring(0,1);

                                 tf1.setText(str);

                                 Thread.sleep(sleeptime);

                          }catch(InterruptedExceptione){

                                 System.out.println(e);

                                 break;

                          }

                   }

            }

            public voidsetButton(){

                   if(this.isAlive())b1.setEnabled(false);

                   if(this.isInterrupted())b2.setEnabled(false);

            }

           

           

     }

 

     @Override

     public void windowClosing(WindowEvente) {

            // TODOAuto-generated method stub

            System.exit(0);

     }

    

 

}

 

 

 


原创粉丝点击