多线程程序设计

2017-03-07  本文已影响21人  hainingwyx

写在之前

以下是《Java8编程入门官方教程》中的一些知识,如有错误,烦请指正。涉及的程序如需下载请移步http://down1.tupwk.com.cn/qhwkdownpage/978-7-302-38738-1.zip

多线程

多任务包括:基于进程的多任务和基于线程的多任务。进程是正在执行的程序,相当于计算机允许同时运行多个程序的功能;线程是最小的可分派代码单元,一个程序可以一次执行多个任务,比如文本编辑器可以在打印的同时格式化文本。

单核系统中并发执行的线程共享CPU,每个线程都收到一个CPU时间片;多核系统中,多个线程可以同时执行。多线程的功能在两个系统中都可以实现。

Thread类和Runnable接口

方法 含义
final String getName() 获取线程名
final int getPriority() 获取线程优先级
final boolean isAlive() 确定线程是否仍在运行
final void join() 等待线程终止
static void sleep(long milliseconds) 按照指定的时间挂起线程,以毫秒为单位
void start() 通过调用run方法启动线程
void run() 线程的进入点

线程创建

两种方法:都要用Thread类来实例化、访问、控制线程,仅仅是创建不同。

  1. 实现Runnable接口
  2. 扩展Thread类

比较:一般仅在通过某些方式增强或者修改类的时候才扩展这些类,因此如果不重写Thread的任何其他方法,最好事先Runnable接口。另外实现Runnable接口可以让线程继承除Thread类外的其他类。

Runnable接口只定义了run方法,在run方法中可以调用其他方法,使用其他类,像主线程一样声明变量。具体的方法通过程序来说明。

// 通过实现Runnable接口创建进程
class MyThread implements Runnable {
  String thrdName;

  MyThread(String name) {
    thrdName = name;
  }

  // Entry point of thread.
  public void run() {
    System.out.println(thrdName + " starting.");
    try {
      for(int count=0; count < 10; count++) {
        Thread.sleep(400);
        System.out.println("In " + thrdName +
                           ", count is " + count);
      }
    }
    catch(InterruptedException exc) {
      System.out.println(thrdName + " interrupted.");
    }
    System.out.println(thrdName + " terminating.");
  }
}

class UseThreads {
  public static void main(String args[]) {
    System.out.println("Main thread starting.");

    // 1.创建一个可运行的线程对象
    MyThread mt = new MyThread("Child #1");

    // 2.在该对象上构造一个线程
    Thread newThrd = new Thread(mt);

    // 3.开始运行线程
    newThrd.start();

    for(int i=0; i<50; i++) {
      System.out.print(".");
      try {
        Thread.sleep(100);//主线程main延迟了5秒,线程mt延迟了4秒,确保main在mt结束之后才终止
      }
      catch(InterruptedException exc) {
        System.out.println("Main thread interrupted.");
      }
    }

    System.out.println("Main thread ending.");
  }
}

改进:MyThread类没必要存储线程名,可以在创建时就为其命名。Thread(Runnable threadob, String name)

//改进版
class MyThread implements Runnable {
  Thread thrd;

  // 建立一个新进程
  MyThread(String name) {
    thrd = new Thread(this, name);//创建时就命名
    thrd.start(); // 开始进程
  }

  // Begin execution of new thread.
  public void run() {
    System.out.println(thrd.getName() + " starting.");
    try {
      for(int count=0; count<10; count++) {
        Thread.sleep(400);
        System.out.println("In " + thrd.getName() +
                           ", count is " + count);
      }
    }
    catch(InterruptedException exc) {
      System.out.println(thrd.getName() + " interrupted.");
    }
    System.out.println(thrd.getName() + " terminating.");
  }
}

class UseThreadsImproved {
  public static void main(String args[]) {
    System.out.println("Main thread starting.");

    MyThread mt = new MyThread("Child #1");s//改进后创建时就启动进程

    for(int i=0; i < 50; i++) {
      System.out.print(".");
      try {
        Thread.sleep(100);
      }
      catch(InterruptedException exc) {
        System.out.println("Main thread interrupted.");
      }
    }

    System.out.println("Main thread ending.");
  }
}

另一种方法:扩展Thread,必须重写作为新建成进入点的run方法。

class MyThread extends Thread {

  // 建立一个新的线程.
  MyThread(String name) {
    super(name); // 线程命名
    start(); // 开始线程
  }

  // 线程运行
  public void run() {
    System.out.println(getName() + " starting.");
    try {
      for(int count=0; count < 10; count++) {
        Thread.sleep(400);
        System.out.println("In " + getName() +
                           ", count is " + count);
      }
    }
    catch(InterruptedException exc) {
      System.out.println(getName() + " interrupted.");
    }

    System.out.println(getName() + " terminating.");
  }
}

class ExtendThread {
  public static void main(String args[]) {
    System.out.println("Main thread starting.");

    MyThread mt = new MyThread("Child #1");

    for(int i=0; i < 50; i++) {
      System.out.print(".");
      try {
        Thread.sleep(100);
      }
      catch(InterruptedException exc) {
        System.out.println("Main thread interrupted.");
      }
    } 

    System.out.println("Main thread ending.");
  }
}

创建多个线程

class MyThread implements Runnable {
  Thread thrd;

  // 构造线程
  MyThread(String name) {
    thrd = new Thread(this, name);

    thrd.start(); // 开始线程
  }

  // 执行线程
  public void run() {
    System.out.println(thrd.getName() + " starting.");
    try {
      for(int count=0; count < 10; count++) {
        Thread.sleep(400);
        System.out.println("In " + thrd.getName() +
                           ", count is " + count);
      }
    }
    catch(InterruptedException exc) {
      System.out.println(thrd.getName() + " interrupted.");
    }
    System.out.println(thrd.getName() + " terminating.");
  }
}

class MoreThreads {
  public static void main(String args[]) {
    System.out.println("Main thread starting.");

    MyThread mt1 = new MyThread("Child #1");//创建并开始执行3个线程
    MyThread mt2 = new MyThread("Child #2");
    MyThread mt3 = new MyThread("Child #3");

    for(int i=0; i < 50; i++) {
      System.out.print(".");
      try {
        Thread.sleep(100);
      }
      catch(InterruptedException exc) {
        System.out.println("Main thread interrupted.");
      }
    } 

    System.out.println("Main thread ending.");
  }
}

确定线程的结束

两种方法:

final boolean isAlive()

class MoreThreads { 
  public static void main(String args[]) { 
    System.out.println("Main thread starting."); 
 
    MyThread mt1 = new MyThread("Child #1"); 
    MyThread mt2 = new MyThread("Child #2"); 
    MyThread mt3 = new MyThread("Child #3"); 
 
    do { 
      System.out.print("."); 
      try { 
        Thread.sleep(100); 
      } 
      catch(InterruptedException exc) { 
        System.out.println("Main thread interrupted."); 
      } 
    } while (mt1.thrd.isAlive() || 
             mt2.thrd.isAlive() || 
             mt3.thrd.isAlive()); //使用Alive等待所有线程终止
 
    System.out.println("Main thread ending."); 
  } 
}

final void join() Throws InterruptedException

等待,直到调用的线程终止

class MyThread implements Runnable {
  Thread thrd;

  // Construct a new thread.
  MyThread(String name) {
    thrd = new Thread(this, name);
    thrd.start(); // start the thread
  }

  // Begin execution of new thread.
  public void run() {
    System.out.println(thrd.getName() + " starting.");
    try {
      for(int count=0; count < 10; count++) {
        Thread.sleep(400);
        System.out.println("In " + thrd.getName() +
                           ", count is " + count);
      }
    }
    catch(InterruptedException exc) {
      System.out.println(thrd.getName() + " interrupted.");
    }
    System.out.println(thrd.getName() + " terminating.");
  }
}

class JoinThreads {
  public static void main(String args[]) {
    System.out.println("Main thread starting.");

    MyThread mt1 = new MyThread("Child #1");
    MyThread mt2 = new MyThread("Child #2");
    MyThread mt3 = new MyThread("Child #3");

    try {
      mt1.thrd.join();//等待,直到线程中终结,下同
      System.out.println("Child #1 joined.");
      mt2.thrd.join();
      System.out.println("Child #2 joined.");
      mt3.thrd.join();
      System.out.println("Child #3 joined.");
    }
    catch(InterruptedException exc) {
      System.out.println("Main thread interrupted.");
    }
    System.out.println("Main thread ending.");
  }
}

线程优先级

可以通过Thread的成员方法来修改线程的优先级。

final void setPriority(int level)

level的值必须在MIN_PRIORITYMAX_PRIORITY的范围内,即1-10.优先级定义为static final变量。

可以通过Thread的成员方法获取当前优先级设置。

final int getPriority

//线程的优先级
class Priority implements Runnable { 
  int count; 
  Thread thrd; 
 
  static boolean stop = false; 
  static String currentName; 
 
  /* Construct a new thread. Notice that this  
     constructor does not actually start the 
     threads running. */ 
  Priority(String name) { 
    thrd = new Thread(this, name); 
    count = 0; 
    currentName = name; 
  } 
 
  // Begin execution of new thread. 
  public void run() { 
    System.out.println(thrd.getName() + " starting."); 
    do { 
      count++; 
 
      if(currentName.compareTo(thrd.getName()) != 0) { 
        currentName = thrd.getName(); 
        System.out.println("In " + currentName); 
      } 
 
    } while(stop == false && count < 10000000); 
    stop = true; 
 
    System.out.println("\n" + thrd.getName() + 
                       " terminating."); 
  }
} 


class PriorityDemo { 
  public static void main(String args[]) { 
    Priority mt1 = new Priority("High Priority"); 
    Priority mt2 = new Priority("Low Priority"); 
 
    // set the priorities 
    mt1.thrd.setPriority(Thread.NORM_PRIORITY+2); 
    mt2.thrd.setPriority(Thread.NORM_PRIORITY-2); 
 
    // start the threads 
    mt1.thrd.start(); 
    mt2.thrd.start(); 
 
    try { 
      mt1.thrd.join(); //等待线程结束
      mt2.thrd.join(); 
    } 
    catch(InterruptedException exc) { 
      System.out.println("Main thread interrupted."); 
    } 
 
    System.out.println("\nHigh priority thread counted to " + 
                       mt1.count); 
    System.out.println("Low priority thread counted to " + 
                       mt2.count); 
  } 
}

同步

同步:控制对象访问的监视器,监视器通过实现“锁”来工作。当一个对象被一个线程锁住后,其他线程就不能访问该对象。当该线程退出时,要为对象解锁,使其他进程可以访问他。有两种同步的方法。

通过synchronized关键字修改方法来同步对方法的访问。当调用方法时,调用线程进入对象监视器,对象监视器锁住对象。对象被锁的同时,其他线程不能进入方法,也不能进入対象定义的其他同步方法。当线程从方法返回时,监视器为对象解锁,允许下一个进程使用对象。

//使用同步方法控制访问
class SumArray { 
  private int sum; 
 
  synchronized int sumArray(int nums[]) { //sumArray()被同步
    sum = 0; // reset sum 
 
    for(int i=0; i<nums.length; i++) { 
      sum += nums[i]; 
      System.out.println("Running total for " + 
             Thread.currentThread().getName() + 
             " is " + sum); 
      try { 
        Thread.sleep(10); // allow task-switch 
      } 
      catch(InterruptedException exc) { 
        System.out.println("Thread interrupted."); 
      } 
    } 
    return sum; 
  } 
}  
 
class MyThread implements Runnable { 
  Thread thrd; 
  static SumArray sa = new SumArray(); 
  int a[]; 
  int answer; 
 
  // Construct a new thread. 
  MyThread(String name, int nums[]) { 
    thrd = new Thread(this, name); 
    a = nums; 
    thrd.start(); // start the thread 
  } 
 
  // Begin execution of new thread. 
  public void run() { 
    int sum; 
 
    System.out.println(thrd.getName() + " starting."); 
 
    answer = sa.sumArray(a);          
    System.out.println("Sum for " + thrd.getName() + 
                       " is " + answer); 
 
    System.out.println(thrd.getName() + " terminating."); 
  } 
} 
 
class Sync { 
  public static void main(String args[]) { 
    int a[] = {1, 2, 3, 4, 5}; 
 
    MyThread mt1 = new MyThread("Child #1", a); 
    MyThread mt2 = new MyThread("Child #2", a); 

    try {
      mt1.thrd.join();
      mt2.thrd.join();
    }
    catch(InterruptedException exc) {
      System.out.println("Main thread interrupted.");
    }

  } 
} 

当上面提出的方法在无法访问源代码时,可以将对这种类定义的方法的调用放入synchronized代码块中。

// Use a synchronized block to control access to SumArray.  
class SumArray {  
  private int sum;  
  
  int sumArray(int nums[]) {  //没有同步!!
    sum = 0; // reset sum  
  
    for(int i=0; i<nums.length; i++) {  
      sum += nums[i];  
      System.out.println("Running total for " +  
             Thread.currentThread().getName() +  
             " is " + sum);  
      try {  
        Thread.sleep(10); // allow task-switch  
      }  
      catch(InterruptedException exc) {  
        System.out.println("Thread interrupted.");  
      }  
    }  
    return sum; 
  }  
}   
  
class MyThread implements Runnable {  
  Thread thrd;  
  static SumArray sa = new SumArray();  
  int a[];  
  int answer; 
 
  // Construct a new thread.  
  MyThread(String name, int nums[]) {  
    thrd = new Thread(this, name);  
    a = nums;  
    thrd.start(); // start the thread  
  }  
  
  // Begin execution of new thread.  
  public void run() {  
    int sum;  
  
    System.out.println(thrd.getName() + " starting.");  
  
    // synchronize calls to sumArray()  
    synchronized(sa) {  //对sumArray的调用被同步
      answer = sa.sumArray(a);           
    }  
    System.out.println("Sum for " + thrd.getName() +  
                       " is " + answer);  
  
    System.out.println(thrd.getName() + " terminating.");  
  }  
}  
  
class Sync {  
  public static void main(String args[]) {  
    int a[] = {1, 2, 3, 4, 5};  
  
    MyThread mt1 = new MyThread("Child #1", a);  
    MyThread mt2 = new MyThread("Child #2", a);  
  
    try {  
      mt1.thrd.join();  
      mt2.thrd.join();  
    } catch(InterruptedException exc) {  
      System.out.println("Main thread interrupted.");  
    }  
  }  
} 

线程通信

一个线程可以通知另一个线程它被阻塞,而其他进程也可以通知它继续执行。Java使用wait()notify()notifyAll()支持进程间通信。三个方法是Object类实现的,是所有对象的一部分,只能在同步环境中被调用。当一个线程暂时阻塞无法运行,它调用wait(),导致进程睡眠,对象的监视器被释放,允许其他线程使用该对象。过一段时间后,当另一个线程进入这个监视器的时候,调用notify()notifyAll(),睡眠进程被唤醒。

final void wait() throws InterruptedException//等待,直到被通知
final void wait(long millis) throws InterruptedException//或者等待一定时间后
final void wait(long millis,int nanos) throws InterruptedException
  
final void notify()     //恢复一个等待线程
final void notifyAll()  //通知所有线程

一个使用wait()和notify()的例子

//比较难,请多次阅读或者运行
class TickTock { 

  String state; // contains the state of the clock
 
  synchronized void tick(boolean running) { 
    if(!running) { // stop the clock 
      state = "ticked";
      notify(); // notify any waiting threads 
      return; 
    } 
 
    System.out.print("Tick "); 

    state = "ticked"; // set the current state to ticked

    notify(); // let tock() run 
    try { 
      while(!state.equals("tocked"))
        wait(); // wait for tock() to complete 
    } 
    catch(InterruptedException exc) { 
      System.out.println("Thread interrupted."); 
    } 
  } 
 
  synchronized void tock(boolean running) { 
    if(!running) { // stop the clock 
      state = "tocked";
      notify(); // notify any waiting threads 
      return; 
    } 
 
    System.out.println("Tock"); 

    state = "tocked"; // set the current state to tocked

    notify(); // let tick() run 
    try { 
      while(!state.equals("ticked"))
        wait(); // wait for tick to complete 
    } 
    catch(InterruptedException exc) { 
      System.out.println("Thread interrupted."); 
    } 
  } 
}  
 
class MyThread implements Runnable { 
  Thread thrd; 
  TickTock ttOb; 
 
  // Construct a new thread. 
  MyThread(String name, TickTock tt) { 
    thrd = new Thread(this, name); 
    ttOb = tt; 
    thrd.start(); // start the thread 
  } 
 
  // Begin execution of new thread. 
  public void run() { 
 
    if(thrd.getName().compareTo("Tick") == 0) { 
      for(int is
    } 
  } 
} 
 
class ThreadCom { 
  public static void main(String args[]) { 
    TickTock tt = new TickTock(); 
    MyThread mt1 = new MyThread("Tick", tt); 
    MyThread mt2 = new MyThread("Tock", tt); 
 
    try { 
      mt1.thrd.join(); 
      mt2.thrd.join(); 
    } catch(InterruptedException exc) { 
      System.out.println("Main thread interrupted."); 
    } 
  } 
}

死锁:一个线程等待另一个线程来做某事,而后者却又在等待前者。这就像两个过于礼貌的谦谦君子,都坚持让对方先通过大门。

竞争:当两个或多个线程尝试同时访问共享资源,但是没有进行合适的同步时,就会发生竞争条件。

挂起、继续执行、停止

一个标志变量用于设置挂起和继续执行,分别是:suspendrunning

一个标志变量用于停止,设置为stop

//挂起、继续执行、停止
class MyThread implements Runnable {  
  Thread thrd;  
  boolean suspended;  //当设置为true时挂起线程
  boolean stopped;  //当设置为true时终止线程
    
  MyThread(String name) {  
    thrd = new Thread(this, name);  
    suspended = false;  
    stopped = false; 
    thrd.start();  
  }  
  
  // This is the entry point for thread.  
  public void run() {  
    System.out.println(thrd.getName() + " starting."); 
    try {  
      for(int i = 1; i < 1000; i++) {  
        System.out.print(i + " ");  
        if((i%10)==0) { 
          System.out.println(); 
          Thread.sleep(250); 
        } 
 
        // Use synchronized block to check suspended and stopped. 
        synchronized(this) {  
          while(suspended) {  
            wait();
          }  
          if(stopped) break; 
        }  
      } 
    } catch (InterruptedException exc) {  
      System.out.println(thrd.getName() + " interrupted.");  
    }  
    System.out.println(thrd.getName() + " exiting.");  
  }  
 
  // Stop the thread.  
  synchronized void mystop() {  
    stopped = true;  
 
   // The following ensures that a suspended thread can be stopped. 
    suspended = false; 
    notify(); 
  }  
 
  // Suspend the thread. 
  synchronized void mysuspend() {++++++++++
    suspended = true;  
  }  
 
  // Resume the thread.  
  synchronized void myresume() { 
    suspended = false;  
    notify();  
  }  
}  
  
class Suspend {  
  public static void main(String args[]) {  
    MyThread ob1 = new MyThread("My Thread");  
 
    try {  
      Thread.sleep(1000); // let ob1 thread start executing 
  
      ob1.mysuspend();  
      System.out.println("Suspending thread.");  
      Thread.sleep(1000); 
 
      ob1.myresume();  
      System.out.println("Resuming thread.");  
      Thread.sleep(1000); 
 
 
      ob1.mysuspend();  
      System.out.println("Suspending thread.");  
      Thread.sleep(1000); 
 
      ob1.myresume();  
      System.out.println("Resuming thread.");  
      Thread.sleep(1000); 
 
      ob1.mysuspend();  
      System.out.println("Stopping thread."); 
      ob1.mystop(); 
    } catch (InterruptedException e) {  
      System.out.println("Main thread Interrupted");  
    }  
  
    // wait for thread to finish  
    try {  
      ob1.thrd.join();  
    } catch (InterruptedException e) {  
      System.out.println("Main thread Interrupted");  
    }  
   
    System.out.println("Main thread exiting.");  
  }  
}

主线程

class UseMain { 
  public static void main(String args[]) { 
    Thread thrd; 
 
    // Get the main thread. 
    thrd = Thread.currentThread(); 
 
    // Display main thread's name. 
    System.out.println("Main thread is called: " + 
                       thrd.getName()); 
 
    // Display main thread's priority. 
    System.out.println("Priority: " + 
                       thrd.getPriority()); 
 
    System.out.println(); 
 
    // Set the name and priority. 
    System.out.println("Setting name and priority.\n"); 
    thrd.setName("Thread #1"); 
    thrd.setPriority(Thread.NORM_PRIORITY+3); 
 
    System.out.println("Main thread is now called: " + 
                       thrd.getName()); 
 
    System.out.println("Priority is now: " + 
                       thrd.getPriority()); 
  } 
}
上一篇下一篇

猜你喜欢

热点阅读