本站不再更新,欢迎光临 java开发技术网
随笔-230  评论-230  文章-8  trackbacks-0

JAVA 多线程系统建立于 Thread 类,它的方法,它的共伴接口 Runnable 基础上, Thread 类封装了多线程的执行。为创建一个新的线程,你的程序必须实现 Runnabel 接口或继承 Thread 类。

Thread 类定义了好几个方法来帮助管理线程,本章用到的方法表如下:

方法

意义

getName

获得线程名

getPrionty

获得线程优先级

jsAlive

判定线程是否仍运行

Join

等侍一个线程终止

Run

线程的入口点

Sleep

在一段时候时挂起线程

Start

通过调用运行的方法来启动线程

 

主线程

任何一个 JAVA 都有一个主线程,当 JAVA 程序启动时一个线程立刻运行,该线程通常叫做程序的主线程。因为它是程序开始执行时就运行,主线程的重要性体现在:

A、 通过它产生期它子线程

B、 通常它必须最后完成执行,因为它执行各种关闭动作。

 

尽管主线程在程序启动时自动创建,但它可以由一个 Thread 对象控制。为此,必须调用 currentThread() 获得它的一个引用, currentThread Thread 类的公有的静态成员:

 static Thread currentThread();

该方法返回一个调用它的线程的引用。一旦获得主线程的引用,就可以像控制其它线程那样控制主线程。

package com.jdk.thread;

 

public class CurrentThreadDemo1 {

       /**

        * @param args

        */

       public static void main(String[] args) {

              Thread t=Thread.currentThread();

              System.out.println("current thread->"+t);

              t.setName("main thread");

              System.out.println("change after thread name->"+t);

              try{

                     for(int i=5;i>0;i--){

                            System.out.println("i-->"+i);

                            t.sleep(1000);

                     }

              }catch(Exception e){

                     e.printStackTrace();

              }

       }

 

}

以上代码是一个最简单的 Thread 方法例子。

创建线程最简单的办法就是实现 Runnable 接口的类, Runnable 操象了一个执行代码单元。为实现 Runnable 接口,一个类仅需实现 Run() 的简单方法,该方法声明如下:

public void run();

run 中可以定义代码来构建新的线程, run 方法能够像主线程那样调用其它方法,引用其它类,声明变量。仅有的不同是 run() 在程序中确立另一个并发程序的入口。当 run 返回时,该线程结束。这是一个例子程序:

 

package com.jdk.thread;

 

class newThread implements Runnable{

       Thread t;

      

       public newThread(){

              t=new Thread(this,"Demo Thread");

              System.out.println("Client Thread ->"+t);

              t.start();

       }

      

       public void run() {

              try{

                     for(int i=5;i>0;i--){

                            System.out.println("Client Thread->"+i);

                            Thread.sleep(500);

                     }

              }catch(Exception e){

                     e.printStackTrace();

              }

              System.out.println(" 子线程结束 ");

       }

      

}

 

public class CurrentThreadDemo2 {

 

       public static void main(String[] args) {

              new newThread();

              try{

                     for(int i=5;i>0;i--){

                            System.out.println("main Thread ->"+i);

                            Thread.sleep(1000);

                     }

              }catch(Exception e){

                     e.printStackTrace();

              }

              System.out.println(" 主线程结束 ");

       }

 

}

通过该例子,我们应该知道 run() 方法是一个多线程的并发入口和结束方法,支持多线程的类必须要实现 Runnable 接口或继承 Thread 类。通常主线程必须是结束运行的最后一个线程(旧版 JVM )。通常在支持多线程的类的构造函数中创建并启动线程,创建线程就生成一个实现了 Runnable 接口的类,启动线程就是调用该类的 start() 方法作用是运行 run() 方法。

 

下面是一个创建多线程的类:

 

package com.jdk.thread;

 

class ThreadDemo3 implements Runnable{

       String threadName;

       Thread t;

       public ThreadDemo3(String tname){

              this.threadName=tname;

              t=new Thread(this,threadName);

              t.start();

       }

       public void run() { 

              try{

                     for(int i=5;i>0;i--){

                            System.out.println(threadName+"-->"+i);

                     }

              }catch(Exception e){

                     e.printStackTrace();

              }

              System.out.println(threadName+" 结束 !");

       }

      

}

 

 

public class Thread3 {

      

       /**

        * @param args

        */

       public static void main(String[] args) {

              ThreadDemo3 td1=new ThreadDemo3("one");

              ThreadDemo3 td2=new ThreadDemo3("two");

              ThreadDemo3 td3=new ThreadDemo3("three");

             

              System.out.println(" 主线程结束 !");

             

       }

 

}

输出结果是:

主线程结束 !

one-->5

one-->4

one-->3

one-->2

one-->1

one 结束 !

two-->5

two-->4

two-->3

two-->2

two-->1

two 结束 !

three-->5

three-->4

three-->3

three-->2

three-->1

three 结束 !

当把上代码改成这样:

package com.jdk.thread;

 

class ThreadDemo3 implements Runnable{

       String threadName;

       Thread t;

       public ThreadDemo3(String tname){

              this.threadName=tname;

              t=new Thread(this,threadName);

              t.start();

       }

       public void run() { 

              try{

                     for(int i=5;i>0;i--){

                            System.out.println(threadName+"-->"+i);

                     }

              }catch(Exception e){

                     e.printStackTrace();

              }

              System.out.println(threadName+" 结束 !");

       }

      

}

 

 

public class Thread3 {

      

       /**

        * @param args

        */

       public static void main(String[] args) {

              ThreadDemo3 td1=new ThreadDemo3("one");

              ThreadDemo3 td2=new ThreadDemo3("two");

              ThreadDemo3 td3=new ThreadDemo3("three");

              try{

                     Thread t=Thread.currentThread();

                     t.sleep(500);

              }catch(Exception e){

                     e.printStackTrace();

              }

              System.out.println(" 主线程结束 !");

             

       }

 

}

结果如下:

one-->5

one-->4

one-->3

one-->2

one-->1

one 结束 !

two-->5

two-->4

two-->3

two-->2

two-->1

two 结束 !

three-->5

three-->4

three-->3

three-->2

three-->1

three 结束 !

主线程结束 !

 

使用 isAlive join

通过前面的例子可以看出我们是使用 sleep ()方法来延时,等待子线程结束,它带来了一个更大的问题是一个线程怎么知道另一个线程已经结束呢?通常有两种方法可以解决:

1、  在线程中调用 isAlive (),这种方法由 Thread 定义,通常形式如下:

final Boolean isAlive();

如果调用的线程还在运行则返回 True ,否则返回 False; isAlive 很少用到,等待线程结束通常使用的方法是调用 join()

2、  join() 形式如下:

final void join()throw InterruptedException

该方法等侍所调用的线程结束,该名字来自于要求线程等待直到指定的线程参与的概念。下面的例子是前面例子的改进,演示用 join() 以确保主线程最后结束。可样也演示了 isAlive() 方法,代码如下:

package com.jdk.thread;

 

class ThreadDemo3 implements Runnable{

       String threadName;

       Thread t;

       public ThreadDemo3(String tname){

              this.threadName=tname;

              t=new Thread(this,threadName);

              t.start();

       }

       public void run() { 

              try{

                     for(int i=5;i>0;i--){

                            System.out.println(threadName+"-->"+i);

                     }

              }catch(Exception e){

                     e.printStackTrace();

              }

              System.out.println(threadName+" 结束 !");

       }

      

}

 

 

public class Thread3 {

      

       public static void main(String[] args) {

             

              ThreadDemo3 td1=new ThreadDemo3("one");

              ThreadDemo3 td2=new ThreadDemo3("two");

              ThreadDemo3 td3=new ThreadDemo3("three");

             

              System.out.println("td1 状态 -->"+td1.t.isAlive());

              System.out.println("td2 状态 -->"+td2.t.isAlive());

              System.out.println("td3 状态 -->"+td3.t.isAlive());

             

              try{

                     System.out.println(" 等待子线程结束 !");

                     td1.t.join();

                     td2.t.join();

                     td3.t.join();

              }catch(Exception e){

                     e.printStackTrace();

              }

             

              System.out.println("td1 状态 -->"+td1.t.isAlive());

              System.out.println("td2 状态 -->"+td2.t.isAlive());

              System.out.println("td3 状态 -->"+td3.t.isAlive());

             

              System.out.println(" 主线程结束 !");

       }

 

}

输出的结果如下:

td1 状态 -->true

td2 状态 -->true

td3 状态 -->true

等待子线程结束 !

one-->5

one-->4

one-->3

one-->2

one-->1

one 结束 !

two-->5

two-->4

two-->3

two-->2

two-->1

two 结束 !

three-->5

three-->4

three-->3

three-->2

three-->1

three 结束 !

td1 状态 -->false

td2 状态 -->false

td3 状态 -->false

主线程结束 !

 

线程的优先级别

 

通常优先级别高的线程比优先级别低的线程获得更多 CPU 时间,但实际与这与很多因素有关。就不要管这么多了,懂怎么设置线程的优选级别就 OK 。设置线程优选级别的方法如下:

final void setPriority(int level) ; 该方法是 Thread 成员方法。 Level 的值通常是 1 10 ,也就是

MIN_PRIORITY MAX_PRIORITY 的范围内。

 

 

线程同步

当两个或两个以上的线程要共享一个资源是,它们需要某种方法来确定同一时刻只能有一个线程占用资源。达到此目的的过程叫做同步 (synchronization)

使用同步方法,当一个线程正在同步方法内所有要访问该同步方法的线程必须等侍,一个例子:

package com.jdk.thread;

 

class Callme{

      

       public void call(String msg){

              System.out.print("["+msg);

              try{

                     Thread.sleep(1000);

              }catch(Exception e){

                     e.printStackTrace();

              }

              System.out.println("]");

       }

}

class Caller implements Runnable{

       String msg;

       Thread t;

       Callme target;

      

       public Caller(Callme targ,String s){

              target=targ;

              msg=s;

              t=new Thread(this);

              t.start();

       }

       public void run() {

              target.call(msg);

       }

 

}

 

public class SynchDemo {

 

       public static void main(String[] args) {

              Callme callme=new Callme();

              Caller c1=new Caller(callme,"Hello"); // 通过多线程创建对象

              Caller c2=new Caller(callme,"JAVA");

              Caller c3=new Caller(callme,"C++");

              try{

                     c1.t.join();

                     c2.t.join();

                     c3.t.join();

              }catch(Exception e){

                     e.printStackTrace();

              }

              System.out.println(" 主线程结束 !");

       }

}

输出的结果是:

[Hello[JAVA[C++]

]

]

主线程结束 ! 主线程结束 !

 

在这里必须要记住多线程的同步访问,只指对同一个对象,也就是说只有同时多个线程访问一个对象的数据或方法时才会出现以上这种情况。因为多线程的 Caller 类,同时访问了同一个对象 callme 的同一个方法 call() 所以就出现以上的输了结果,显然这不是我们想要的。

如果我们在 Callme 类的 call ()方法前加上 synchronized 方法如下:

   public synchronized void call()

得到的结束就是 :

[Hello]

[JAVA]

[C++]

主线程结束 !

 

 

线程间的通讯

为了避免轮询, JAVA 包含了通过 wait() notify() notifyAll() 实现一个进程间的通信机制。这些方法在对象中是用 final 的方法实现的。所以所有的类都含有它们,这三个方法仅在 synchronized 方法中可以调用。

Wait() 告知被调用的线程放弃管程,进入睡眠直到其它线程进入相同的管程并调用 notify()

Notify() 恢复相同对象中第一个调用 wait() 的线程。

notifyAll() 恢复相同对象中所有调用 wait() 的线程,具有最高优先级的最先运行。

这些方法在 Object 类中被声明如下:

public void wait() throws InterruptedException

public void waitAll();

public void notify();

下面是一个不使用经程间通信的例程,它输入的结果并不是我们想要的,代码如下:

 

 

 

package com.jdk.thread;

 

class Q{

       int n;

       synchronized int get(){

              System.out.println("get "+n);

              return n;

       }

       synchronized void put(int vn){

              this.n=vn;

              System.out.println("put "+n);

       }

}

class Producer implements Runnable{

       Q q;

       public Producer(Q vq){

              this.q=vq;

              new Thread(this,"Producer").start();

       }

      

       public void run() {

              int i=0;

              while(true){

                     q.put(i++);

              }

       }

      

}

class Consumer implements Runnable{

      

       Q q;

       public Consumer(Q vq){

              this.q=vq;

              new Thread(this,"Consumer").start();

       }

       public void run() {

             

              while(true){

                     q.get();

              }

       }

      

}

 

public class SynchDemo1 {

 

       public static void main(String[] args) {

              Q q=new Q();

              new Producer(q);

              new Consumer(q);

              System.out.println(" 主线程结束 !");

       }

 

}

尽管在 Q 类中的 put ()和 get() 方法是同步的,没有东西阻止生产者超越消费者。也没有东西阻止消费者消费同样序列多次,所以输出结果如下:

 

get 19000

put 19001

get 19001

put 19002

get 19002

 

通常把 Q 类改成如下,但我还是有点不理解,为什么输出结果不是从 1 开始呢?进程中的线程是怎么通信的呢?

class Q{

       int n;

       boolean valueSet=false;

       synchronized int get(){

              if(!valueSet){

                     try{

                            wait();

                     }catch(Exception e){

                            e.printStackTrace();

                     }

              }

              System.out.println("get "+n);

              valueSet=false;

              notify();

              return n;

       }

       synchronized void put(int vn){

              if(valueSet){

                     try{

                            wait();

                     }catch(Exception e){

                            e.printStackTrace();

                     }

              }

              this.n=vn;

              valueSet=true;

              System.out.println("put "+n);

              notify();

       }

}

死锁

需要避免的与多任务和理有关的特殊的错误类型是死锁,死锁发生在当两个线程对一对同步对象有循环的依懒关系时。

 

 

线程挂起、恢复、终止

 

posted on 2006-10-07 20:48 有猫相伴的日子 阅读(369) 评论(0)  编辑  收藏 所属分类: jdk

只有注册用户登录后才能发表评论。


网站导航:
 
本站不再更新,欢迎光临 java开发技术网