java获得当前线程有两种方法,第一种是Thread.current thread infoThread();谁知道另外一种?

java创建线程的三种方式及其对比-程序设计-就爱阅读网
您还可以使用以下方式登录
当前位置:&>&&>&&>& > java创建线程的三种方式及其对比
java创建线程的三种方式及其对比
Java中创建线程主要有三种方式:一、继承Thread类创建线程类(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。(2)创建Thread子类的实例,即创建了线程对象。(3)调用线程对象的start()方法来启动该线程。package com.public class FirstThreadTest extends Thread{int i = 0;//重写run方法,run方法的方法体就是现场执行体public void run(){for(;i<100;i++){System.out.println(getName()+"
"+i);}}public static void main(String[] args){for(int i = 0;i< 100;i++){System.out.println(Thread.currentThread().getName()+"
: "+i);if(i==20){new FirstThreadTest().run();new FirstThreadTest().run();}}}}上述代码中Thread.currentThread()方法返回当前正在执行的线程对象。GetName()方法返回调用该方法的线程的名字。二、通过Runnable接口创建线程类(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。(3)调用线程对象的start()方法来启动该线程。示例代码为:package com.public class RunnableThreadTest implements Runnable{public void run(){for(i = 0;i <100;i++){System.out.println(Thread.currentThread().getName()+" "+i);}}public static void main(String[] args){for(int i = 0;i < 100;i++){System.out.println(Thread.currentThread().getName()+" "+i);if(i==20){RunnableThreadTest rtt = new RunnableThreadTest();new Thread(rtt,"新线程1").start();new Thread(rtt,"新线程2").start();}}}}三、通过Callable和Future创建线程(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回&#20540;。(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回&#20540;。(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回&#20540;实例代码:package com.import java.util.concurrent.Cimport java.util.concurrent.ExecutionEimport java.util.concurrent.FutureTpublic class CallableThreadTest implements Callable{public static void main(String[] args){CallableThreadTest ctt = new CallableThreadTest();FutureTask ft = new FutureTask(ctt);for(int i = 0;i < 100;i++){System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);if(i==20){new Thread(ft,"有返回值的线程").start();}}try{System.out.println("子线程的返回值:"+ft.get());} catch (InterruptedException e){e.printStackTrace();} catch (ExecutionException e){e.printStackTrace();}}@Overridepublic Integer call() throws Exception{int i = 0;for(;i<100;i++){System.out.println(Thread.currentThread().getName()+" "+i);}}}二、创建线程的三种方式的对比采用实现Runnable、Callable接口的方式创见多线程时,优势是:线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。劣势是:编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。使用继承Thread类的方式创建多线程时优势是:编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。劣势是:线程类已经继承了Thread类,所以不能再继承其他父类。就爱阅读网友整理上传,为您提供最全的知识大全,期待您的分享,转载请注明出处。
您可能也喜欢这些1.线程的概念:线程(thread)是指一个任务从头至尾的执行流,线程提供一个运行任务的机制,对于java而言,一个程序中可以并发的执行多个线程,这些线程可以在多处理器系统上同时运行。当程序作为一个应用程序运行时,java解释器为main()方法启动一个线程。
2.并行与并发:
(1)并发:在单处理器系统中,多个线程共享CPU时间,而操作系统负责调度及分配资源给它们。
(2)并行:在多处理器系统中,多个处理器可以同时运行多个线程,这些线程在同一时间可以同时运行,而不同于并发,只能多个线程共享CPU时间,同一时间只能运行一个线程。
3.线程的创建:
(1)基础概念:java中每个任务就是一个可运行对象,为了创建任务,必须首先定义任务类,任务类必须实现Runnable接口。而线程本质上讲就是便于任务执行的对象。一个线程的执行过程就是一个任务类中run()方法的执行到结束。
(2)通过Runnable接口创建线程:
  a.定义一个任务类实现Runnable接口,实现Runnable接口中的run()方法(run()方法告知系统线程该如何运行),run()方法中定义具体的任务代码或处理逻辑。
  b.定义了任务类后,为任务类创建一个任务对象。
  c.任务必须在线程中执行,创建一个Tread类的对象,将前面创建的实现了Runnable接口的任务类对象作为参数传递给Tread类的构造方法。
  d.调用Tread类对象的start()方法,启动一个线程。它会导致任务的run()方法被执行,当run()方法执行完毕,则线程就终止。
  实例代码:
1 package com.muzeet.
3 //每个任务都是Runable接口的一个实例,任务是可运行对象,线程是便于任务执行的对象。必须创建任务类,重写run方法定义任务
4 public class ThreadDemo1 implements Runnable {
private int countDown = 10;
//重写run方法,定义任务
public void run() {
while(countDown-- &0)
System.out.println("$" + Thread.currentThread().getName()
+ "(" + countDown + ")");
//调用start方法会启动一个线程,导致任务中的run方法被调用,run方法执行完毕则线程终止
public static void main(String[] args) {
Runnable demo1 = new ThreadDemo1();
Thread thread1 = new Thread(demo1);
Thread thread2 = new Thread(demo1);
thread1.start();
thread2.start();
System.out.println("火箭发射倒计时:");
  程序运行结果:
火箭发射倒计时:
$Thread-0(9)
$Thread-0(8)
$Thread-0(7)
$Thread-0(6)
$Thread-0(5)
$Thread-0(4)
$Thread-0(3)
$Thread-0(2)
$Thread-0(1)
$Thread-0(0)
  同时运行两个任务对象:
public static void main(String[] args) {
Runnable demo1 = new ThreadDemo1();
Runnable demo2 = new ThreadDemo1();
Thread thread1 = new Thread(demo1);
Thread thread2 = new Thread(demo2);
thread1.start();
thread2.start();
System.out.println("火箭发射倒计时:");
  运行结果:
火箭发射倒计时:
$Thread-0(9)
$Thread-0(8)
$Thread-0(7)
$Thread-0(6)
$Thread-1(9)
$Thread-0(5)
$Thread-1(8)
$Thread-0(4)
$Thread-1(7)
$Thread-0(3)
$Thread-1(6)
$Thread-1(5)
$Thread-0(2)
$Thread-1(4)
$Thread-1(3)
$Thread-1(2)
$Thread-1(1)
$Thread-1(0)
$Thread-0(1)
$Thread-0(0)
(3)继承Thread类来创建线程: 
  a.首先创建一个任务类extends Thread类,因为Thread类实现了Runnable接口,所以自定义的任务类也实现了Runnable接口,重新run()方法,其中定义具体的任务代码或处理逻辑。
  b.创建一个任务类对象,可以用Thread或者Runnable作为自定义的变量类型。
  c.调用自定义对象的start()方法,启动一个线程。
  示例代码:
1 package com.muzeet.
3 //每个任务都是Runable接口的一个实例,任务是可运行对象,线程即可运行对象。必须创建任务类,重写run方法定义任务
4 public class ExtendFromThread extends Thread {
private int countDown = 10;
//重写run方法,定义任务
public void run() {
while(countDown-- &0)
System.out.println("$" + this.getName()
+ "(" + countDown + ")");
//调用start方法会启动一个线程,导致任务中的run方法被调用,run方法执行完毕则线程终止
public static void main(String[] args) {
ExtendFromThread thread1 = new ExtendFromThread();
ExtendFromThread thread2 = new ExtendFromThread();
thread1.start();
thread2.start();
System.out.println("火箭发射倒计时:");
  运行结果: 
火箭发射倒计时:
$Thread-0(9)
$Thread-0(8)
$Thread-0(7)
$Thread-0(6)
$Thread-0(5)
$Thread-0(4)
$Thread-0(3)
$Thread-0(2)
$Thread-0(1)
$Thread-0(0)
$Thread-1(9)
$Thread-1(8)
$Thread-1(7)
$Thread-1(6)
$Thread-1(5)
$Thread-1(4)
$Thread-1(3)
$Thread-1(2)
$Thread-1(1)
$Thread-1(0)
一个线程等待另一个线程结束后再执行:当执行PrintNum这个任务时,打印到数字50时,转而去执行打印字符C这个任务,知道线程thread4执行完才继续执行打印数字任务。
1 package com.muzeet.testT
3 public class PrintNum implements Runnable {
private int lastN
public PrintNum(int n)
public void run() {
// TODO Auto-generated method stub
Thread thread4 = new Thread(new PrintChar('c', 40));
thread4.start();
for(int i=1;i&=lastNi++)
System.out.println(" " + i);
if(i == 50)
thread4.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
4.两种方法的比较(转载)
首先分析两种方式的输出结果,同样是创建了两个线程,为什么结果不一样呢?
使用实现Runnable接口方式创建线程可以共享同一个目标对象(TreadDemo1 tt=new TreadDemo1();),实现了多个相同线程处理同一份资源。当第一个线程执行完任务后,countDown已经为0,所以第二个线程就不会输出。而继承Thread创建线程的方式,new出了两个任务类对象,有各自的成员变量,相互之间不干扰。
然后再看一段来自JDK的解释:
Runnable&接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run&的无参数方法。
设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread&类实现了Runnable。激活的意思是说某个线程已启动并且尚未停止。
此外,Runnable&为非&Thread&子类的类提供了一种激活方式。通过实例化某个Thread&实例并将自身作为运行目标,就可以运行实现Runnable&的类。大多数情况下,如果只想重写run()&方法,而不重写其他&Thread&方法,那么应使用Runnable&接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。(推荐使用创建任务类,并实现Runnable接口,而不是继承Thread类)
采用继承Thread类方式:(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。采用实现Runnable接口方式:(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。
阅读(...) 评论()最全面的用法解析,如果你对Java的多线程机制并没有深入的研究,那么本文可以帮助你更透彻地理解Java多线程的原理以及使用方法。
1.创建线程
在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);
方法一:继承Thread类覆盖run方法
public class ThreadDemo1 {
public static void main(String[] args){
Demo d = new Demo();
d.start();
for(int i=0;i&60;i++){
System.out.println(Thread.currentThread().getName()+i);
class Demo extends Thread{
public void run(){
for(int i=0;i&60;i++){
System.out.println(Thread.currentThread().getName()+i);
public class ThreadDemo2 {
public static void main(String[] args){
Demo2 d =new Demo2();
Thread t = new Thread(d);
t.start();
for(int x=0;x&60;x++){
System.out.println(Thread.currentThread().getName()+x);
class Demo2 implements Runnable{
public void run(){
for(int x=0;x&60;x++){
System.out.println(Thread.currentThread().getName()+x);
2.线程的生命周期
与人有生老病死一样,线程也同样要经历开始(等待)、运行、挂起和停止四种不同的状态。这四种状态都可以通过Thread类中的方法进行控制。下面给出了Thread类中和这四种状态相关的方法。
// 开始线程
publicvoid start( );
publicvoid run( );
// 挂起和唤醒线程
publicvoid resume( );
// 不建议使用
publicvoid suspend( );
// 不建议使用
publicstaticvoid sleep(long millis);
publicstaticvoid sleep(long millis, int nanos);
// 终止线程
publicvoid stop( );
// 不建议使用
publicvoid interrupt( );
// 得到线程状态
publicboolean isAlive( );
publicboolean isInterrupted( );
publicstaticboolean interrupted( );
// join方法
publicvoid join( ) throws InterruptedE
线程在建立后并不马上执行run方法中的代码,而是处于等待状态。线程处于等待状态时,可以通过Thread类的方法来设置线程不各种属性,如线程的优先级(setPriority)、线程名(setName)和线程的类型(setDaemon)等。
当调用start方法后,线程开始执行run方法中的代码。线程进入运行状态。可以通过Thread类的isAlive方法来判断线程是否处于运行状态。当线程处于运行状态时,isAlive返回true,当isAlive返回false时,可能线程处于等待状态,也可能处于停止状态。下面的代码演示了线程的创建、运行和停止三个状态之间的切换,并输出了相应的isAlive返回值。
一但线程开始执行run方法,就会一直到这个run方法执行完成这个线程才退出。但在线程执行的过程中,可以通过两个方法使线程暂时停止执行。这两个方法是suspend和sleep。在使用suspend挂起线程后,可以通过resume方法唤醒线程。而使用sleep使线程休眠后,只能在设定的时间后使线程处于就绪状态(在线程休眠结束后,线程不一定会马上执行,只是进入了就绪状态,等待着系统进行调度)。
在使用sleep方法时有两点需要注意:
1. sleep方法有两个重载形式,其中一个重载形式不仅可以设毫秒,而且还可以设纳秒(1,000,000纳秒等于1毫秒)。但大多数操作系统平台上的Java虚拟机都无法精确到纳秒,因此,如果对sleep设置了纳秒,Java虚拟机将取最接近这个值的毫秒。
2. 在使用sleep方法时必须使用throws或try{&#8230;}catch{&#8230;}。因为run方法无法使用throws,所以只能使用try{&#8230;}catch{&#8230;}。当在线程休眠的过程中,使用interrupt方法中断线程时sleep会抛出一个InterruptedException异常。sleep方法的定义如下:
publicstaticvoid sleep(long millis) throws InterruptedException
publicstaticvoid sleep(long millis, int nanos) throws InterruptedException
有三种方法可以使终止线程。
使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。
使用interrupt方法中断线程。
1. 使用退出标志终止线程
当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的。如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想让循环永远运行下去,可以使用while(true){&#8230;}来处理。但要想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。下面给出了一个利用退出标志终止线程的例子。
join方法的功能就是使异步执行的线程变成同步执行。也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方法。如果不使用join方法,就不能保证当执行到start方法后面的某条语句时,这个线程一定会执行完。而使用join方法后,直到这个线程退出,程序才会往下执行。下面的代码演示了join的用法。
3.多线程安全问题
问题原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来执行,导致共享数据的错误。
解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不执行。
同步代码块:
public class ThreadDemo3 {
public static void main(String[] args){
Ticket t =new Ticket();
Thread t1 = new Thread(t,"窗口一");
Thread t2 = new Thread(t,"窗口二");
Thread t3 = new Thread(t,"窗口三");
Thread t4 = new Thread(t,"窗口四");
t1.start();
t2.start();
t3.start();
t4.start();
class Ticket implements Runnable{
private int ticket =400;
public void run(){
while(true){
synchronized (new Object()) {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if(ticket&=0)
System.out.println(Thread.currentThread().getName()+"---卖出"+ticket--);
public class ThreadDemo3 {
public static void main(String[] args){
Ticket t =new Ticket();
Thread t1 = new Thread(t,"窗口一");
Thread t2 = new Thread(t,"窗口二");
Thread t3 = new Thread(t,"窗口三");
Thread t4 = new Thread(t,"窗口四");
t1.start();
t2.start();
t3.start();
t4.start();
class Ticket implements Runnable{
private int ticket = 4000;
public synchronized void
saleTicket(){
if(ticket&0)
System.out.println(Thread.currentThread().getName()+"卖出了"+ticket--);
public void run(){
while(true){
saleTicket();
同步函数锁是this 静态同步函数锁是class
线程间的通信
public class ThreadDemo3 {
public static void main(String[] args){
class Person{
public void set(String name,String gender){
this.name =
this.gender =
public void get(){
System.out.println(this.name+"...."+this.gender);
final Person p =new Person();
new Thread(new Runnable(){
public void run(){
while(true){
p.set("张三", "男");
p.set("lili", "nv");
x=(x+1)%2;
}).start();
new Thread(new Runnable(){
public void run(){
while(true){
}).start();
张三....男
张三....男
lili....nv
lili....男
张三....nv
lili....男
修改上面代码
public class ThreadDemo3 {
public static void main(String[] args){
class Person{
public void set(String name,String gender){
this.name =
this.gender =
public void get(){
System.out.println(this.name+"...."+this.gender);
final Person p =new Person();
new Thread(new Runnable(){
public void run(){
while(true){
synchronized (p) {
p.set("张三", "男");
p.set("lili", "nv");
x=(x+1)%2;
}).start();
new Thread(new Runnable(){
public void run(){
while(true){
synchronized (p) {
}).start();
lili....nv
lili....nv
lili....nv
lili....nv
lili....nv
lili....nv
张三....男
张三....男
张三....男
张三....男
等待唤醒机制
*线程等待唤醒机制
*等待和唤醒必须是同一把锁
public class ThreadDemo3 {
private static boolean flags =
public static void main(String[] args){
class Person{
public void set(String name,String gender){
this.name =
this.gender =
public void get(){
System.out.println(this.name+"...."+this.gender);
final Person p =new Person();
new Thread(new Runnable(){
public void run(){
while(true){
synchronized (p) {
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
p.set("张三", "男");
p.set("lili", "nv");
x=(x+1)%2;
p.notifyAll();
}).start();
new Thread(new Runnable(){
public void run(){
while(true){
synchronized (p) {
if(!flags)
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
p.notifyAll();
}).start();
生产消费机制一
public class ThreadDemo4 {
private static boolean flags =
public static void main(String[] args){
class Goods{
public synchronized void produce(String name){
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
this.name =name+"编号:"+num++;
System.out.println("生产了...."+this.name);
notifyAll();
public synchronized void consume(){
if(!flags)
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("消费了******"+name);
notifyAll();
final Goods g =new Goods();
new Thread(new Runnable(){
public void run(){
while(true){
g.produce("商品");
}).start();
new Thread(new Runnable(){
public void run(){
while(true){
g.consume();
}).start();
生产消费机制2
public class ThreadDemo4 {
private static boolean flags =
public static void main(String[] args){
class Goods{
public synchronized void produce(String name){
while(flags)
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
this.name =name+"编号:"+num++;
System.out.println(Thread.currentThread().getName()+"生产了...."+this.name);
notifyAll();
public synchronized void consume(){
while(!flags)
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(Thread.currentThread().getName()+"消费了******"+name);
notifyAll();
final Goods g =new Goods();
new Thread(new Runnable(){
public void run(){
while(true){
g.produce("商品");
},"生产者一号").start();
new Thread(new Runnable(){
public void run(){
while(true){
g.produce("商品");
},"生产者二号").start();
new Thread(new Runnable(){
public void run(){
while(true){
g.consume();
},"消费者一号").start();
new Thread(new Runnable(){
public void run(){
while(true){
g.consume();
},"消费者二号").start();
消费者二号消费了******商品编号:48049
生产者一号生产了....商品编号:48050
消费者一号消费了******商品编号:48050
生产者一号生产了....商品编号:48051
消费者二号消费了******商品编号:48051
生产者二号生产了....商品编号:48052
消费者二号消费了******商品编号:48052
生产者一号生产了....商品编号:48053
消费者一号消费了******商品编号:48053
生产者一号生产了....商品编号:48054
消费者二号消费了******商品编号:48054
生产者二号生产了....商品编号:48055
消费者二号消费了******商品编号:48055
热门栏目订阅二次元同好交流新大陆
扫码下载App
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
接着要创建该子类的对象,此时一个新的线程就被创建了,创建新线程时会用到Thread 类定义的如下两个构造函数:
◆public Thread()
◆public Thread(String name)
其中,第一个构造函数是Thread类默认的构造函数,不指定参数;第二个构造函数可以为新建的线程指定一个名称,该名称就是字符串参数name的值。
建立了新的线程对象以后,它并不运行,而是直到调用了该对象的start()方法,该方法在Thread 类中定义,在Thread 类的子类中被覆盖。它的作用是启动一个新的线程,并在该线程上运行子类对象中的run()方法。
start()方法声明格式为:
public void start()
示例如下所示:
SubThread s = new SubThread();&& // 创建Thread子类的对象
s.start(); // 启动一个新的线程
当一个类继承Thread类时,它必须重写run()方法,这个方法是新线程的入口。如&&&& 果Thread类的这个子类没有覆盖run()方法,那么程序会调用Thread类的run()方法,只&&& 不过该run()方法什么也不做,此时新线程一创建就结束了。这种线程对程序来说是没有&
任何意义的,所以在这里提醒读者在创建线程的时候一定不要忘了覆盖Thread类的run()方法。
下面举一个完整的例子来演示通过扩展Thread类创建线程的过程。程序代码如下所示:
// 例4.1.1& ThreadDemo.java
class NewThread extends Thread& // 通过继承Thread类来创建一个新的线程
NewThread()// 构造方法
super("Thread Demo");&&& // 定义线程的名字
System.out.println("New thread: " + getName());
public void run()& // 覆写run()方法,这是线程的入口
while( true )
System.out.println(Thread.currentThread().getName()+
"& is running");
class ThreadDemo
public static void main(String args[])
NewThread thd = new NewThread(); // 创建一个新线程
thd.start();&&&&&&&&& //启动线程,调用NewThread类对象的run()方法
可以看到,新的线程是由实例化NewThread类的对象创建的,该NewThread类可以通过继承java.lang.Thread类来得到。其中,在NewThread类中,构造函数里调用了super()方法。该方法将调用父类Thread下列形式的构造函数:
public Thread(String threadName)
这里,threadName指定线程名称(当然也可以不指定线程的名称,而由系统自动为新建线程提供名称)。在NewThread类中通过覆写 run()方法来规定线程所要实现的内容。此外,需要注意的是,启动新线程执行时必须调用start()方法。程序结果如图4.1.1所示:在上面的代码中,使用了Thread类的currentThread()静态方法来获得当前程序执行时所对应的那个线程对象,又通过线程对象的 getName()方法,得到了当前线程的名字。这些方法都可以在JDK帮助文档中查到。因此,善于利用JDK帮助文档来获取有关类的更多信息,可以方便 程序的编写。
在上面代码的run()方法中,由于循环条件始终为true,因此,屏幕上会不断地输出Thread Demo is running,新建的线程永远不会结束,这当然不是所希望的结果。这里所希望的是可以合理的设置循环条件来有效地控制线程的终止。所以,在run()方 法中使用到循环控制的时候一定要小心使用,否则局面难以控制。
其实,针对前面的程序做一些改动。可以让这个程序实现一个非常有用的功能。
// 例4.1.2&
ThreadDemo2.java
class NewThread extends Thread // 通过继承Thread类来创建一个新的线程
NewThread(String name)&& // 构造方法
super(name);
public void run()& // 重写run()方法,这是线程的入口
for( int i=10 ; i&0 ;i--)& // 循环执行10次
System.out.println("left time: "+ i);
Thread.sleep(1000);&& //当前线程睡眠1000毫秒
}catch(InterruptedException e){&&&& //处理异常
System.out.println(e.getMessage());
System.out.println("game is over,bye!");
class ThreadDemo2
public static void main(String args[])
NewThread thd = new NewThread("Thread Demo"); // 创建一个新的线程
thd.start();&&&&&&&&& //启动线程,调用NewThread类对象的run()方法
程序输出结果如图4.1.2 所示:通过这个程序看到了什么?在run()方法体中,实现了一个倒计时的功 能。线程通过循环控制,每隔一秒输出一次剩余的时间,循环结束时输出"game is over,bye!",线程也随之结束。可见这个程序中新建的线程不是死循环,而是通过一些条件来对线程的起始进行了控制,从而实现了倒计时的功能。
在这个程序中,还可以看到,在给线程起名字的时候可以通过创建线程的时候来实现。因为查阅JDK的帮助文档,会发现Thread类除了默认的构造函 数之外,还有很多带参数的构造函数,只不过在这里是用到了public Thread(String name)这个构造方法。
并不是在创建线程对象的时候给线程起个名字就可以了,还应该在线程类的子类中定义相应的构造函数才行,这个构造函数的形式如下:
SubThread(String name)&& // 线程子类的构造方法
super(name);
如果不这样做,程序编译会提示错误,读者可以想想为什么。也可以将上面程序中NewThread类的构造方法注释掉,编译一下程序,看到错误提示后,再去思考这个问题。
在这个程序中还用到了try…catch语句,它用来捕获程序中可能发生的异常,而产生异常的原因是程序中使用了Thread.sleep()这样的方法。通过查阅JDK的帮助文档,可以看到线程类的sleep()方法的完整格式如下:
public static void sleep(long millis) throws
InterruptedException
看到这个throws关键字,想必读者就应知道为什么使用try…catch语句了。由于这个方法可能会抛出一个中断异常,因此,有必要在程序调用这个方法时对可能发生的异常进行处理。此外,这个方法是静态的,所以可以通过类名直接调用。
2、实现Runnable接口来创建线程
除了扩展Thread类可以创建线程之外,还可以通过定义一个实现了Runnable接口的类来创建线程。为了将来程序执行时可以进入线程,在这个类中必须实现Runnable接口中唯一提供的run()方法。
示例如下所示:
class OneThread implements Runnable
public void run()
// 新建线程所要完成的工作
当定义好一个实现了Runnable接口的类以后,还不能直接去创建线程对象,要想真正去创建一个线程,还必须在类的内部实例化一个Thread类的对象。此时,会用到Thread 类定义的如下两个构造函数:
public Thread(Runnable target)
public Thread(Runnable target,String name)
在这两个构造函数中,参数target定义了一个实现了Runnable接口的类的对象引用。新建的线程将来就是要执行这个对象中的run()方法。而新建线程的名字可以通过第二个构造方法中的参数name来指定。
示例如下所示:
OneThread onethread = new OneThread();
Thread newthread = new Thread(onethread);
此时,新线程对象才被创建,如果想要执行该线程的run()方法,则仍然需要通过调用start()方法来实现。例如:
newthread.start();
要想创建新的线程对象,这两条语句缺一不可。此后程序会在堆内存中实实在在地创建一个OneThread类的实例对象,该对象中包含了一个线程对象 newthread。newthread对象会通过调用start()方法来执行它自己的run()方法。随着run()方法的结束,线程对象 newthread的生命也将结束,但是onethread对象还会存在于堆内存当中。如果希望在实际编程当中一旦线程结束,即释放与线程有关的所有资
源,可以使用创建匿名对象的方法来创建这个线程,格式如下所示:
new Thread(new OneThread).start();
这样一来,该线程一旦运行结束,所有与该线程有关的资源都将成为垃圾,这样就可以在特定的时间内被Java的垃圾回收机制予以回收,释放所占用内存,提高程序的效率。
下面这个程序是通过实现Runnable接口来创建的线程,可以将它和前面的例4.1.2的程序进行比较。
// 例4.1.3&
ThreadDemo3.java
class NewThread implements Runnable // 实现了Runnable接口
public void run() // 覆写Runnable 接口中唯一的run()方法,这是线程的入口
for( int i=10 ; i&0 ;i--)
System.out.println("left time: "+ i);
Thread.sleep(1000);&& //当前线程睡眠1000毫秒
}catch(InterruptedException e){&&&& //处理异常
System.out.println(e.getMessage());
System.out.println("game is over,bye!");
class ThreadDemo3
public static void main(String args[])
NewThread newthread = new NewThread();
Thread thd = new Thread(newthread, "Thread Demo")
thd.start();&&&&&&&&& //启动线程,调用run()方法
编译并运行这个程序,可以看到程序执行的结果和例4.1.2的程序输出的结果是完全一样的,因此,读者可以在创建线程的时候选择任意一种方式来实现
为了使程序达到优异的性能,可以利用创建线程来完成那些任务。因为一个线
程就是一个独立的执行通道,在没有特殊的要求之下,多个线程之间彼此独立运行,互不干扰。而且带线程的程序通常比没有带线程的程序运行得要快,因此线程常 用在网络和图形用户界面等程序设计当中,这一优势在多处理器的计算机上更加明显。本节中不仅要理解什么是线程,而且还应掌握两种创建线程的方法,为以后在
程序中使用多线程技术打下坚实的基础。
学习了本节以后,有很多读者都会问到这样的问题:为什么Java要提供两种方法来创建线程呢?它们都有哪些区别?相比而言,哪一种方法更好呢?
在Java中,类仅支持单继承,也就是说,当定义一个新的类的时候,它只能扩展一个外部类.这样,如果创建自定义线程类的时候是通过扩展 Thread类的方法来实现的,那么这个自定义类就不能再去扩展其他的类,也就无法实现更加复杂的功能。因此,如果自定义类必须扩展其他的类,那么就可以
使用实现Runnable接口的方法来定义该类为线程类,这样就可以避免Java单继承所带来的局限性。
还有一点最重要的就是使用实现Runnable接口的方式创建的线程可以处理同一资源,从而实现资源的共享,这一点会在第4.2节中介绍。
如果程序当中没有显式地创建线程,那么是不是程序中就没有线程存在呢?其实,当Java程序启动时,有一个线程立刻就会运行,该线程是自动创建的,它就是程序的主线程(main
thread),它在程序开始时就执行了。
主线程的产生可以完成两方面的任务:
◆它是产生其他子线程的线程
◆通常它必须最后完成执行,这样它可以执行各种关闭操作。
下面举一个能够显示主线程运行状态的例子,程序代码如下。
// 例4.1.4&
ThreadDemo4.java
class NewThread extends Thread
NewThread(String name)
super(name);
public void run()&&&
for (int count = 10,row = 0; row & 10; row++)& //输出10行*
for (int i = 0; i & i++)
System.out.print('*');
System.out.println();
System.out.println(currentThread().getName()+"& is over");
class ThreadDemo4
public static void main(String argv[])
// 下面两行代码用来新建一个线程
NewThread thd = new NewThread("new Thread");&
thd.start();&&&&&&&
// 下面的代码用来控制主线程
for(int i=0;i&10;i++)
System.out.println(Thread.currentThread().getName()+"& is
running");
System.out.println(Thread.currentThread().getName()+" is over");
尽管主线程在程序启动时自动创建,但它可以被一个Thread对象控制。要想这样做,必须在主类中调用Thread类的方法currentThread()来获得主线程的一个引用。
再来研究一下这个Thread类的currentThread()方法到底都做了什么,通过查阅JDK帮助文档,发现该方法是Thread类的公有的静态成员。它的语法形式如下:
static Thread currentThread( )
该方法如果在主类中被使用,那么它将返回主线程的引用,如果在一个Thread类的派生子类中被使用,则它将返回由该派生子类所产生的新线程的引用。因此,一旦获得主线程的引用,就可以像控制其他线程那样控制主线程了。
编译程序并运行,得到这样的结果:
main is running
main is running
main is running
main is running
**********
**********
**********
main is running
main is running
main is running
main is running
main is running
main is running
main is over
**********
**********
**********
**********
**********
**********
**********
new Thread is over
从结果来看,并不是先输出10行“**********”符号,然后再输出10行"main is running",而是交错输出。这就是因为采用了线程的方式,由于操作系统在调度线程的时候并不是按顺序进行的,而是将时间片轮流分给每一个线程,具体
每一次分给哪个线程也是不确定的,但可以保证在很短的时间内,每一个线程都有被执行的机会,因此程序显示出了上面的结果。当然,如果再次运行程序,还会得 到不同的输出结果。当循环的次数越多,输出的结果越能说明这个问题。
随机性地分配时间片给一个线程使用并不是我们所期望的结果,引入线程是为了能够充分利用系统资源,但如果程序中存在很多线程,那么程序的输出结果会
因为这种随机性而变得面目全非。为了更好地控制多个线程之间能够合理地使用时间片,可以通过一些方法来合理地调度线程,从而既能够正确地输出期望的结果, 又充分利用系统资源。想了解有关内容,读者可以参考第4.2节。
前面提到程序的生命周期时是这样介绍的:程序从main()方法这个入口进入,在main()方法中可以调用其他方法和成员或者其他类及类的方法和
成员,main()方法执行完毕,整个程序也就结束了。但是在这个程序中可以看到这样的情况,即new Thread这个线程结束的时间是在主线程结束之后。这就说明Java允许其他线程在主线程之后结束。也证明这样一个事实,那就是,只有当所有线程都执行
结束时,整个程序才真正结束。可见,前面的说法并无错误,只不过这里引入了线程的概念
阅读(3996)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_082065',
blogTitle:'Java创建线程的两种方法',
blogAbstract:' ',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:5,
publishTime:4,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

我要回帖

更多关于 currentthread 作用 的文章

 

随机推荐