关与线程

来源:互联网 发布:小猪cms创始人陈允 编辑:程序博客网 时间:2024/04/29 08:06

线程:(好东西)

为什么要使用线程:

1、  提高系统的吞吐率或使用效率。(I/0等待)

2、  提供灵敏的用户操作。

举例:

 

第一部分 原理

定义:

程序内部顺序执行的指令序列。线程本身不拥有资源(没有自己的资源),如内存空间。但是它可以使用进程的资源。

线程与进程的区别:

1、  从资源分配的角度

进程是资源分配的基本单位,而线程本身没有资源。

2、  从程序调度的角度

进程可以包含多个线程,是程序调度的基本单位。

3、  从系统的开销角度

进程的创建过程的系统开销大与线程创建过程的时间开销,因为进程创建需要为他分配资源,而此过程的系统消开销是很大的,而线程共享进程的资源,无需要进行分配。

4、  从并发性的角度

进程与线程在执行过程中都可以并发的进行,但并发的粒度不同。进程的并发表现为应用级的并发,如:如放歌与编写程序。而线程的并发表现在应用内部的功能性并发,如:电影中的图像与声音。

举例说明:

1、  进程与线程

2、  很好的例用线程,必须明确原理

进程的状态:

进程运行的必要条件:

1、  拥有资源

2、  拥有CPU时间

三态:

运行状态:当线程在处理机上运行的状态程为运行状态(拥有资源和CPU)

就绪状态:当线程拥有资源但没有CPU时间时,等CPU时间的状态。

阻塞状态:当线程等待资源的时的状态。

五态:

新建:刚刚创建还没有提交的状态。

终止:结束运行。

第二部分 Java中的线程。

线程的创建:

两种创建方式:

1、  继承Thread类。

  声明一个 Thread 类的子类,并覆盖 run() 方法。

  class mythread extends Thread {

   public void run( ) {/* 覆盖该方法*/ }

  }

 

2、  实现Runnable接口。

声明一个实现 Runnable 接口的类,并实现 run() 方法。

       class mythread implements Runnable{

   public void run( ) {/* 实现该方法*/ }

 }

Ex1:

public class CreateWinthThread extends Thread {

  private int countDown = 5;

  private static int threadCount = 0;

  public SimpleThread() {

    super("" + ++threadCount); // Store the thread name

    start();

  }

  public String toString() {

    return "#" + getName() + ": " + countDown;

  }

  public void run() {

    while(true) {

      System.out.println(this);

      if(--countDown == 0) return;

    }

  }

  public static void main(String[] args) {

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

      new CreateWinthThread ();

   }

}

线程的主要方法:

Run():在此方法中编写线程所要完成的功能。

Start():将线程从新建装态改为就绪状态。

线程就绪以后实际的执行是由JVMOS负责。

l         执行的时间是无法确定的(多线程中)

l         执行的顺序是无法确定的(多线程中)

l         执行的结果是无法确定的(多线程中)

继承Thread常用的几种构造函数:

l         Thread(),用缺省名称创建一个Thread对象 

l         Thread(String name),用指定的name参数的名称创建一个Thread对象

l         Thread(Runnable target) 用实现了Runnable接口的类创建一个Thread对像

l         Thread(Runnable target, String name) 用实现了Runnable接口的类创建一个Thread对像,线程为name参数指定的名称。

 

 

 

 

Ex2:

public class CreateWithRunnable implements Runnable {

       private int countDown = 100;

         public String toString() {

           return "#" + Thread.currentThread().getName() +

             ": " + countDown;

         }

         public void run() {

           while(true) {

             System.out.println(this);

             if(--countDown == 0) return;

           }

         }

         public static void main(String[] args) {

           for(int i = 1; i <= 5; i++)

             new Thread(new CreateWithRunnable(), "" + i).start();     

         }

}

 

currentThread():得到当前线程

getName():得到线程的名称

Runnable接口中只有一个Run方法,没有start()无法将线程从新建态转为就绪态,所以无法运行线程。必须把Runnable转为Thread类。才可以运行。

 

创建反应敏捷的用户界面

public class FriendlyUI {

       private static int i = 0;

       public static void main(String[] args) {

              new StopRun().start();

              Compute compute = new Compute();

              compute.setI(i);

              compute.start();

       }

}

 

class StopRun extends Thread {

       private String flag = "";

 

       public void setFlag() {

              try {

                     InputStreamReader reader = new InputStreamReader(System.in);

                     BufferedReader input = new BufferedReader(reader);

                     System.out.println("如果要终止程序请输入  exit");

                     this.flag = input.readLine();

 

              } catch (IOException e) {

                     e.printStackTrace();

              }

       }

 

       public void run() {

              while (!flag.equals("exit")) {

                     this.setFlag();

              }

              System.exit(0);

       }

}

 

class Compute extends Thread {

       private int i = 0;

       public void setI(int i) {

              this.i = i;

       }

       public int getI() {

              return i;

       }

       public void run() {

              while (true) {

                     i++;

              }

       }

}

 

 

sleep ():让它停一段以毫秒计的时间

Yielding():把线程的控制权转交其它线程

Join():待线程处理完之后才转交控制权

守护线程(精灵线程、监控线程、服务线程)

所谓"守护线程(daemon thread)"是指,只要程序还在运行,它就应该在后台提供某种公共服务的线程,但是守护线程不属于程序的核心部分。因此,当所有非守护线程都运行结束的时候,程序也结束了。相反,只要还有非守护线程在运行,程序就不能结束。比如,运行main( )的线程就属于非守护线程

 

 

 

 

 

Ex3(sleep,yield,join)

public class YieldingThread extends Thread {

         private static Test monitor = new Test();

         private int countDown = 100;

         private static int threadCount = 0;

         public YieldingThread() {

           super("" + ++threadCount);

           start();

         }

         public String toString() {

           return "#" + getName() + ": " + countDown;

         }

         public void run() {

           while(true) {

             System.out.println(this);

             if(--countDown == 0) return;

             //yield();

             try {

                     sleep(1000);

                      

              } catch (InterruptedException e) {

                            e.printStackTrace();

              }

           }

         }

         public static void main(String[] args) {

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

                     try {

                            new YieldingThread().join();

                     } catch (InterruptedException e) {

                            // TODO 自动生成 catch

                            e.printStackTrace();

                     }

                     //new YieldingThread();

         }

       }

友好用户界面的例字

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

 

public class FriendlyUI {

       private static int i = 0;

       public static void main(String[] args) {

              new StopRun().start();

              Compute compute = new Compute();

              compute.setI(i);

              compute.start();

       }

}

 

class StopRun extends Thread {

       private String flag = "";

 

       public void setFlag() {

              try {

                     InputStreamReader reader = new InputStreamReader(System.in);

                     BufferedReader input = new BufferedReader(reader);

                     System.out.println("如果要终止程序请输入  exit");

                     this.flag = input.readLine();

 

              } catch (IOException e) {

                     e.printStackTrace();

              }

       }

 

       public void run() {

              while (!flag.equals("exit")) {

                     this.setFlag();

              }

              System.exit(0);

       }

}

 

class Compute extends Thread {

       private int i = 0;

       public void setI(int i) {

              this.i = i;

       }

       public int getI() {

              return i;

       }

       public void run() {

              while (true) {

                     i++;

              }

       }

}

线程之间的优先级:

1-10

NORM_PRIORITY=5

MIN_PRIORITY=1

MAX_PRIORITY=10

通过 setPriority()进行设置

虽然JDK提供了10级优先级,但是却不能很好地映射到很多操作系统上。比方说,Windows 2000平台上有7个等级还没固定下来,因此映射是不确定的(虽然SunSolaris231个等级)。要想保持可移植性,唯一的办法就是,在调整优先级的时候,盯住MIN_PRIORITY, NORM_PRIORITY, MIN_PRORITY

 

线程之间的协作

l         线程互斥使用资源

l         线程同步

 

线程互斥使用资源:

 临界区:一段共公的内存空间或设备,为两个或两个以上的线程所使用。

各线程共同使用临界区的时候可能会产生冲突。

public class CreateMutexThread extends Thread {

       static VarClass varClass = new VarClass();

       /*

          run方法中的内容为线程的中要执行的内容

        */

       public void run(){

        while(true){

             varClass.setI();

             int number=0;

             number=varClass.getI();      

             if((number%2)!=0){

             System.out.println(getName()+"   "+ varClass.getI());

             System.exit(0);

             }

        }   

       }

 

       public static void main(String[] args) {

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

              new CreateMutexThread().start();

              }

       }

}

 

class VarClass{

       int i=0;

       public void setI(){

              i++;

              i++;

       }

       public int getI(){

         return i;     

       }

}

解决办法:

代码的前后设一条加锁和解锁的语句,这样同一时刻只有一个线程能够执行这段代码。

每个对象都有一个锁(也称监控器monitor),它是对象生来就有的东西(因此你不必为此写任何代码)。当你调用synchronized方法时,这个对象就被锁住了。在方法返回并且解锁之前,谁也不能调用同一个对象的其它synchronized方法。就说上面那两个方法,如果你调用了f( ),那么在f( )返回并且解锁之前,你是不能调用同一个对象的g( )的。因此对任何一个特定的对象,所有的synchronized方法都会共享一个锁,而这个锁能防止两个或两个以上线程同时读写一块共用内存

public class CreateMutexThread extends Thread {

       static VarClass varClass = new VarClass();

       /*

          run方法中的内容为线程的中要执行的内容

        */

       public void run(){

        while(true){

             varClass.setI();

             int number=0;

             number=varClass.getI();      

             if((number%2)!=0){

             System.out.println(getName()+"   "+ varClass.getI());

             System.exit(0);

             }

        }   

       }

 

       public static void main(String[] args) {

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

              new CreateMutexThread().start();

              }

       }

}

 

class VarClass{

       int i=0;

       synchronized public void setI(){

              i++;

              i++;

       }

       Synchronized public int getI(){

         return i;     

       }

}

同步:

一个线程的结果是另一个线程运行的条件时用到。

class Order {

         private static int i = 0;

         private int count = i++;

         public Order() {

           if(count == 10) {

             System.out.println("Out of food, closing");

             System.exit(0);

           }

         }

         public String toString() { return "Order " + count; }

       }

       class WaitPerson extends Thread {

         private Restaurant restaurant;

         public WaitPerson(Restaurant r) {

           restaurant = r;

           start();

         }

         public void run() {

           while(true) {

             while(restaurant.order == null)

               synchronized(this) {

                 try {

                   wait();

                 } catch(InterruptedException e) {

                   throw new RuntimeException(e);

                 }

               }

             System.out.println(

               "Waitperson got " + restaurant.order);

             restaurant.order = null;

           }

         }

       }

       class Chef extends Thread {

         private Restaurant restaurant;

         private WaitPerson waitPerson;

         public Chef(Restaurant r, WaitPerson w) {

           restaurant = r;

           waitPerson = w;

           start();

         }

         public void run() {

           while(true) {

             if(restaurant.order == null) {

               restaurant.order = new Order();

               System.out.print("Order up! ");

               synchronized(waitPerson) {

                 waitPerson.notify();

               }

             }

             try {

               sleep(100);

             } catch(InterruptedException e) {

               throw new RuntimeException(e);

             }

           }

         }

       }

       public class Restaurant {

      

         Order order; // Package access

         public static void main(String[] args) {

           Restaurant restaurant = new Restaurant();

           WaitPerson waitPerson = new WaitPerson(restaurant);

           Chef chef = new Chef(restaurant, waitPerson);

         

         }

       }

同步例2

public class TestThread {

    static ShareDate shareDate=new ShareDate();

       public static void main(String[] args) {

              SetValue setValue=new SetValue(shareDate);

              setValue.start();

              new GetValue(shareDate,setValue).start();

       }

}

 

class ShareDate{

 

       private String[] strValue=new String[10];

       private int index=0;

       synchronized public String getStrValue(){

              index--;

              return strValue[index+1];

       }

       synchronized public void setStrValue(String value){

              index++;

              this.strValue[index-1]=value;

       }

       synchronized public int getIndex(){

              return index;

       }

}

class GetValue extends Thread{

       private ShareDate shareDate;

       private SetValue setValue;

       private int index;

       public GetValue(ShareDate shareDate,SetValue setValue){

              this.shareDate=shareDate;

              this.setValue=setValue;

       }

       public void run(){       

              while(true){

                     index=shareDate.getIndex();

                     System.out.println("GetValue"+index);

                   if (index==0){

                      synchronized(setValue){                       

                                   setValue.notify();                     

                      }

                      try {

                                   sleep(100);

                            } catch (InterruptedException e) {

                                   // TODO 自动生成 catch

                                   e.printStackTrace();

                            }

                          yield();

                         

                   }else if (index>=0 && index<=9){

                          System.out.println(shareDate.getStrValue());      

                   }

              }

             

       }

}

class SetValue extends Thread{

       private ShareDate shareDate;

       int index;

       public SetValue(ShareDate shareDate){

              this.shareDate=shareDate;

             

       }

       public void run(){

              int i=0;

       while(true){

              this.index=shareDate.getIndex();

              System.out.println("SetValue"+index);

             

              if (index>=9){

                  synchronized (this){

                   try {

                            this.wait();

                     } catch (InterruptedException e) {

                            // TODO 自动生成 catch

                            e.printStackTrace();

                     }     

                  }     

              }else{

                     shareDate.setStrValue(""+i);

                     i++;

              }

             

             

       }     

       }

}

三部分:总结

1、  线程的创建(两种创建方式)

2、  线程的属性与方法

3、  线程的状态

线程的状态

线程的状态可归纳为以下四种:

  1. New: 线程对象已经创建完毕,但尚未启动(start),因此还不能运行。

  2. Runnable: 处在这种状态下的线程,只要分时机制分配给它CPU周期,它就能运行。也就是说,具体到某个时点,它可能正在运行,也可能没有运行,但是轮到它运行的时候,谁都不能阻止它;它没有dead,也没有被阻塞。

  3. Dead: 要想中止线程,正常的做法是退出run( )。在Java 2以前,你也可以调用stop( ),不过现在不建议用这个办法了,因为它很可能会造成程序运行状态的不稳定。此外还有一个destroy( )(不过它还没有实现,或许将来也不会了,也就是说已经被放弃了)。后面我们会讲怎样用其它办法来实现stop( )的功能。

  4. Blocked: 就线程本身而言,它是可以运行的,但是有什么别的原因在阻止它运行。线程调度机制会直接跳过blocked的线程,根本不给它分配CPU的时间。除非它重新进入runnable状态,否则什么都干不了。

进入阻塞状态

如果线程被阻塞了,那肯定是出了什么问题。问题可能有以下几种:

  1. 你用sleep(milliseconds)方法叫线程休眠。在此期间,线程是不能运行的。

  2. 你用wait( )方法把线程挂了起来。除非收到notify( )notifyAll( )消息,否则线程无法重新进入runnable状态。这部分内容会在后面讲。

  3. 线程在等I/O结束。

  4. 线程要调用另一个对象的synchronized方法,但是还没有得到对象的锁。

或许你还在旧代码里看到过suspend( )resume( ),不过Java 2已经放弃了这两个方法(因为很容易造成死锁),所以这里就不作介绍了。

课后习题:

l         了解守护线程

l         线程共享使用资源

l         线程互斥使用资源

l         线程同步

原创粉丝点击