创建和启动java线程

原文地址

原作者:Jakob Jenkov

翻译者:呼啸 

反馈邮箱:274021963@qq.com

java的线程是一个对象,如其他任何java对象一样。线程是类java.lang.Thread的实例,或者是这个类的子类的实例。

在java中你可以这样创建线程:

Thread  thread = new Thread();

你可以调用这个线程对象的start()方法去启动它:

Thread.start();

在这个例子中,这个线程并没有执行任何代码。因此,它会马上停止。

你有两种方式可以指定线程要执行的代码:

第一种就是去创建一个Thread的子类并且重写其Run()方法。第二种方法是通过让一个对象实现Runnable()接口,并且也要重写Run()方法。


Thread子类

给一个线程指定所执行的代码的第一种方法是:去创建一个Thread的子类,并且重写其run()方法。这个run()方法会在你调用satrt()方法后被线程执行。这里有个例子:

public class MyThread extends Thread{
	public void run(){
		System.out.println("myThread running!");
	}
}

去创建和启动上面的线程,你可以这样做:

MyThread myThread = new MyThread();
		myThread.start();

start()方法的调用会在线程启动之后立即停止,在run()方法执行后开始等待。Run()方法执行时好像是被一个不同的CPU调用的。当这个run()方法执行时会打印出”MyThread running”字样。

你也可以创建一个匿名的Thread子类,像这样:

Thread thread = new Thread(){
			public void run(){
				System.out.println("Thread Ruuning!");
			}
		};(译者注:原文中此处少了分号,应为作者笔误)
		thread.start();

当run()方法被新线程调用的时候这个例子会打印出”Thread Running”字样。


实现Runnable接口

给一个线程指定要执行的代码的第二种方法是创建一个类让他实现java.lang.Runnable接口。这个实现了Runable对象可以被一个线程执行:


public class MyRunnable implements Runnable{
	public void run(){
		System.out.println("MyRunnable running!");
	}
}

在一个Thread的构造函数中通过一个MyRunnable的实例,可以让这个线程执行MyRunable的run()方法。来看下代码:

Thread thread = new Thread(new MyRunnable());
		thread.start();

当这个线程启动之后,他会执行MyRunnable实例的run()方法而不是她自己的run()方法。上面的例子会打印出"MyRunnable running!"的字样。

你也可以创建一个匿名类来实现Runnable接口,像这样:

Runnable myRunnable = new Runnable() {
			
			@Override
			public void run() {
				System.out.println("Runnable running!");
				
			}
		};(译者注:原文中此处少了分号,应为作者笔误)
		Thread thread = new Thread(myRunnable);
		thread.start();

子类或者Runnable接口?

没有规则规定这两个方法中,哪个是更好的。就我个人而言,我比较喜欢实现Runnable接口并且传递一个实现了Thread实例的实例(译者注:作为参数)。(译者注:如果大家对我翻译的这句难以理解,参照原文。原文是: I prefer implementing Runnable, and handing aninstance of the implementation to a Thread instance.)当一个线程池去执行一个Runnable实例的时候,如果线程池里没有线程是空闲的,他很容易做到给这个Runnable实例排队。而这一点对于Thread子类来说,很难做到。

有时你不得不实现Runnable接口以及Thread子类。例如,你创建一个Thread子类他可以实现多个Runnable接口。当你想实现一个线程池的时候通常都采用这种方案。


常见的陷阱:调用run()方法而不是start()方法

当创建和启动一个线程的时候一个常见的错误就是去调用这个线程的run()方法而不是start()方法,就像这样:

Thread newThread = new Thread(new MyRunnable());(译者注:此处原作者在MyRunnable()前少了关键字new,应为笔误)
		newThread.run(); //本应该是start()方法

在开始的时候你可能没发现什么问题,因为这个Runable的run()方法如你所料的执行了。然而,这个run()方法并不是你刚才所创建的线程(译者注:指的是newThread对象)所执行的。并不是这个线程执行的run()方法,而是这个run()方法创建了这个线程。换句话说,这个线程执行了上面两行代码,新创建的线程调用执行了MyRunable实例的run()方法。(译者注:可能有些绕人,可以这么理解,第一行代码创建一个线程对象newThread.第二行代码又创建了一个线程。我们暂且称之为tempThreadtempThread执行了MyRunnable实例的run()方法)对于这个newThread,你必须调用它的start()方法。


线程名称

当你创建了一个线程,你可以给予他一个名称。这个名称可以让你把它同其他的线程区分开来。例如有多个线程在使用System.out输出内容的时候,你可以很轻易地看出是哪个线程输出的文本。这儿有一个例子:

	Thread thread  = new Thread("New Thread"){
			public void run(){
				System.out.println("run by:"+getName());
			}
		};
		thread.start();
		System.out.println(thread.getName());
	}


注意那个”New Thread”字符串作为一个参数传递给Thread的构造器。这个字符串是这个线程的名称。可以通过线程的getName()方法获得线程的名称。当你在使用一个Runnable接口的实现时你也可以传递一个名称给这个线程。请看:

MyRunnable runnable = new MyRunnable();
		Thread thread = new Thread(runnable,"New Thread");
		thread.start();
		System.out.println(thread.getName());

注意:无论怎么样,只要MyRunable类不是Thread的子类,他就没有权限使thread的getName方法去执行。可以使用下面的代码获得当前执行的线程:

Thread.currentThread();

获得当前执行的线程的名称,可以这样做:

String threaName = Thread.currentThread().getName();

一个线程例子

这里有一个小例子。首先他打印出了当前执行这个main()方法的线程的名称。这个线程是JVM分配的。然后他启动了10个线程并且都给他们一个数字作为名称(“”+i)。每个线程随后打印出自己名称。然后停止执行。


public class ThreadExample {
	public static void main(String []args){
		System.out.println(Thread.currentThread().getName());
		for(int i=0;i<10;i++){
			new Thread(""+i){
				public void run(){
					System.out.println("Thread: "+getName()+"running");
				}
			}.start();
parallel		}
		
	}
	
}

注意即使线程按顺序启动(1,2,3等等)但他们也许不按顺序执行。意味着thread1也许不是第一个将他的名字写入System.out的。这是因为原则上线程是并行执行的而不是顺序的。JVM 和(或者)操作系统决定线程执行的顺序。这个顺序和那些线程启动的顺序并不一定相同。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值