Java多线程初学者指南(2):用Thread类建设线程
副标题#e#
在Java中建设线程有两种要领:利用Thread类和利用Runnable接口。在利用Runnable接口时需要成立一个Thread实例。因此,无论是通过Thread类照旧Runnable接口成立线程,都必需成立Thread类或它的子类的实例。Thread类的结构要领被重载了八次,结构要领如下:
public Thread( );
public Thread(Runnable target);
public Thread(String name);
public Thread(Runnable target, String name);
public Thread(ThreadGroup group, Runnable target);
public Thread(ThreadGroup group, String name);
public Thread(ThreadGroup group, Runnable target, String name);
public Thread(ThreadGroup group, Runnable target, String name, long stackSize);
Runnable target
实现了Runnable接口的类的实例。要留意的是Thread类也实现了Runnable接口,因此,从Thread类担任的类的实例也可以作为target传入这个结构要领。
String name
线程的名子。这个名子可以在成立Thread实例后通过Thread类的setName要领配置。假如不配置线程的名子,线程就利用默认的线程名:Thread-N,N是线程成立的顺序,是一个不反复的正整数。
ThreadGroup group
当前成立的线程所属的线程组。假如不指定线程组,所有的线程都被加到一个默认的线程组中。关于线程组的细节将在后头的章节具体接头。
long stackSize
线程栈的巨细,这个值一般是CPU页面的整数倍。如x86的页面巨细是4KB。在x86平台下,默认的线程栈巨细是12KB。
一个普通的Java类只要从Thread类担任,就可以成为一个线程类。并可通过Thread类的start要领来执行线程代码。固然Thread类的子类可以直接实例化,但在子类中必需要包围Thread类的run要领才气真正运行线程的代码。下面的代码给出了一个利用Thread类成立线程的例子:
001 package mythread;
002
003 public class Thread1 extends Thread
004 {
005 public void run()
006 {
007 System.out.println(this.getName());
008 }
009 public static void main(String[] args)
010 {
011 System.out.println(Thread.currentThread().getName());
012 Thread1 thread1 = new Thread1();
013 Thread1 thread2 = new Thread1 ();
014 thread1.start();
015 thread2.start();
016 }
017 }
上面的代码成立了两个线程:thread1和thread2。上述代码中的005至008行是Thread1类的run要领。当在014和015行挪用start要领时,系统会自动挪用run要领。在007行利用this.getName()输出了当前线程的名字,由于在成立线程时并未指定线程名,因此,所输出的线程名是系统的默认值,也就是Thread-n的形式。在011行输出了主线程的线程名。
上面代码的运行功效如下:
main
Thread-0
Thread-1
从上面的输出功效可以看出,第一行输出的main是主线程的名子。后头的Thread-1和Thread-2别离是thread1和thread2的输出功效。
#p#副标题#e#
留意:任何一个Java措施都必需有一个主线程。一般这个主线程的名子为main。只有在措施中成立别的的线程,才气算是真正的多线程措施。也就是说,多线程措施必需拥有一个以上的线程。
Thread类有一个重载结构要领可以配置线程名。除了利用结构要领在成立线程时配置线程名,还可以利用Thread类的setName要领修改线程名。要想通过Thread类的结构要领来配置线程名,必需在Thread的子类中利用Thread类的public Thread(String name)结构要领,因此,必需在Thread的子类中也添加一个用于传入线程名的结构要领。下面的代码给出了一个配置线程名的例子:
001 package mythread;
002
003 public class Thread2 extends Thread
004 {
005 private String who;
006
007 public void run()
008 {
009 System.out.println(who + ":" + this.getName());
010 }
011 public Thread2(String who)
012 {
013 super();
014 this.who = who;
015 }
016 public Thread2(String who, String name)
017 {
018 super(name);
019 this.who = who;
020 }
021 public static void main(String[] args)
022 {
023 Thread2 thread1 = new Thread2 ("thread1", "MyThread1");
024 Thread2 thread2 = new Thread2 ("thread2");
025 Thread2 thread3 = new Thread2 ("thread3");
026 thread2.setName("MyThread2");
027 thread1.start();
028 thread2.start();
029 thread3.start();
030 }
031
在类中有两个结构要领:
第011行:public sample2_2(String who)
这个结构要领有一个参数:who。这个参数用来标识当前成立的线程。在这个结构要领中仍然挪用Thread的默认结构要领public Thread( )。
第016行:public sample2_2(String who, String name)
#p#分页标题#e#
这个结构要领中的who和第一个结构要领的who的寄义一样,而name参数就是线程的名名。在这个结构要领中挪用了Thread类的public Thread(String name)结构要领,也就是第018行的super(name)。
在main要领中成立了三个线程:thread1、thread2和thread3。个中thread1通过结构要领来配置线程名,thread2通过setName要领来修改线程名,thread3未配置线程名。
运行功效如下:
thread1:MyThread1
thread2:MyThread2
thread3:Thread-2
从上面的输出功效可以看出,thread1和thread2的线程名都已经修改了,而thread3的线程名仍然为默认值:Thread-2。thread3的线程名之所以不是Thread-1,而是Thread-2,这是因为在024行成立thread2时已经将Thread-1占用了,因此,在025行成立thread3时就将thread3的线程名设为Thread-2。然后在026行又将thread2的线程名修改为MyThread2。因此就会获得上面的输出功效。
留意:在挪用start要领前后都可以利用setName配置线程名,但在挪用start要领后利用setName修改线程名,会发生不确定性,也就是说大概在run要领执行完后才会执行setName。假如在run要领中要利用线程名,就会呈现固然挪用了setName要领,但线程名却未修改的现象。
Thread类的start要领不能多次挪用,如不能挪用两次thread1.start()要领。不然会抛出一个IllegalThreadStateException异常。