- 浏览: 47190 次
- 性别:
- 来自: 北京
文章分类
最新评论
转载:http://supportopensource.iteye.com/blog/771786
在Java中创建线程有两种方法:继承Thread类和实现Runnable接口。
一、继承Thread类创建线程类(Thread类已经实现了Runnable接口)
1、Thread类的构造方法有8个,但常用的只有4个,分别为:
Thread类中的两个最主要的方法:
(1)run()—包含线程运行时所执行的代码,即线程需要完成的任务,是线程执行体。
(2)start()—用于启动线程。
2、通过继承Thread类来创建并启动多线程的步骤:
(1)定义Thread类的子类,并覆盖该类的run()方法。
(2)创建Thread子类的实例,即创建线程对象。
(3)用线程对象的start()方法来启动该线程。
例程1:
public class Thread1 extends Thread{ public void run(){ System.out.println(this.getName()); } public static void main(String args[]){ System.out.println(Thread.currentThread().getName()); Thread1 thread1 = new Thread1(); Thread1 thread2 = new Thread1(); thread1.start(); thread2.start(); } }
程序的运行结果如下:
main
Thread-0
Thread-1
注意:程序中两条线程并发执行时,每次的执行结果是会变化的。这是因为,如果多个没有同步约束关系的线程并发执行时,调度线程将不能保证哪个线程先执行及其持续的时间,在不同平台上,或在同一平台上不同时刻的多次运行可能会得到不同的结果。
Java中对于线程启动后唯一的能够保障的就是:“每个线程都将启动,每个线程都会执行结束”。但谁会先执行谁会后执行,将没有保障,也就是说,就算一个线程在另一个线程之前启动,也无法保障该线程一定在另一个线程之前执行完毕。
程序分析如下:
(1)任何一个Java程序都必须有一个主线程。主线程的线程执行体不是由run()方法来确定的,而是由main()方法来确定的:main()方法的方法体代表主线程的线程执行体。
(1)上面程序用到线程的两个方法:
Thread.currentThread():currentThread()是Thread类的静态方法,该方法总是返回当前正在执行的线程对象的引用。
getName():该方法是Thread类的实例方法,该方法返回调用该方法的线程的名字。
(3)程序可以通过setName(String name)方法为线程设置名字,也可以通过getName()方法返回指定线程的名字。在默认情况下,主线程的名字为main,用户启动的多条线程的名字依次为:Thread-0、Thread-1、Thread-2、……、Thread-n等。
(4)一个线程只能被启动一次。否则会抛出java.lang.IllegalThreadStateException异常。
例程2:
public class Thread2 extends Thread{ private String who; public void run(){ System.out.println(who+":"+this.getName()); } public Thread2(String who){ super(); this.who = who; } public Thread2(String who,String name){ super(name); this.who = who; } public static void main(String args[]){ Thread2 thread1 = new Thread2("thread1","MyThread1"); Thread2 thread2 = new Thread2("thread2"); Thread2 thread3 = new Thread2("thread3"); thread2.setName("MyThread2"); thread1.start(); thread2.start(); thread3.start(); } }
程序的运行结果如下:
thread1:MyThread1
thread2:MyThread2
thread3:Thread-1
结果分析:
thread1通过调用了Thread类的public Thread(String name)构造方法来设置线程名称。
thread2通过setName()方法来修改线程名称。
thread3未设置线程名称。
注意:在调用start方法前后都可以使用setName()方法设置线程名,但在调用start()方法后使用setName()修改线程名称,会产生不确定性,也就是说可能在run()方法执行完后才会去执行setName()方法,此时,如果在run方法中要使用线程名,就会出现虽然调用了setName()方法,但线程名称却未修改的现象。
例程3:
public class TestThread1{ public static void main(String args[]){ Thread t1 = new Thread3(); Thread t2 = new Thread3(); t1.start(); t2.start(); } } class Thread3 extends Thread{ public void run(){ for(int i=0;i<10;i++){ System.out.println(this.getName()+":"+i); } } }
程序的运行结果如下:
Thread-0:0
Thread-0:1
Thread-1:0
Thread-0:2
Thread-0:3
Thread-0:4
Thread-1:1
Thread-0:5
Thread-0:6
Thread-1:2
Thread-0:7
Thread-1:3
Thread-0:8
Thread-1:4
Thread-0:9
Thread-1:5
Thread-1:6
Thread-1:7
Thread-1:8
Thread-1:9
结果分析:
从以上结果可以看出:Thread-0和Thread-1两条线程各自都会输出的i变量,比如存在Thread-0:5和Thread-1:5,因为i是FirstThread类的实例变量,而不是局部变量,而每次创建线程对象都需要创建一个FirstThread对象,所以Thread-0和Thread-1不能共享该实例属性。因而可以得出以下结论:使用继承Thread类的方法来创建线程类,多条线程之间无法共享线程类的实例变量。
二、实现Runnable接口创建线程类
实现Runnable接口的类必须使用Thread类的实例才能创建线程。通过实现Runnable接口来创建并启动多线程的步骤:
(1)定义Runnable接口的实现类,并实现该接口的run()方法。
(2)创建Runnable实现类的实例,然后将该实例作为参数传入Thread类的构造方法来创建Thread对象。
(3)用线程对象的start()方法来启动该线程。
例程5:
public class MyRunnable implements Runnable{ public void run(){ System.out.println(Thread.currentThread().getName()); } public static void main(String args[]){ MyRunnable r1 = new MyRunnable(); MyRunnable r2 = new MyRunnable(); MyRunnable r3 = new MyRunnable(); Thread thread1 = new Thread(r1,"MyThread1"); Thread thread2 = new Thread(r2); thread2.setName("MyThread2"); Thread thread3 = new Thread(r3); thread1.start(); thread2.start(); thread3.start(); } }
程序的运行结果如下:
MyThread1
MyThread2
Thread-1
当然,实现Runnable接口的类的对象可以被同时传给多个线程对象。上述程序修改如下:
MyRunnable r1 = new MyRunnable(); Thread thread1 = new Thread(r1,"MyThread1"); Thread thread2 = new Thread(r1); thread2.setName("MyThread2"); Thread thread3 = new Thread(r1); thread1.start(); thread2.start(); thread3.start();
运行的结果是类似的。
例程6:
public class TestThread2{ public static void main(String args[]){ Runnable1 r1 = new Runnable1(); Thread t1 = new Thread(r1); Thread t2 = new Thread(r1); t1.start(); t2.start(); } } class Runnable1 implements Runnable{ public void run(){ for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } }
程序的运行结果如下:
Thread-0:0
Thread-1:0
Thread-1:1
Thread-0:1
Thread-1:2
Thread-0:2
Thread-1:3
Thread-1:4
Thread-1:5
Thread-0:3
Thread-1:6
Thread-0:4
Thread-1:7
Thread-0:5
Thread-1:8
Thread-0:6
Thread-1:9
Thread-0:7
Thread-0:8
Thread-0:9
例程7:
public class SecondThread implements Runnable{ private int i; public void run(){ for(;i<10;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } public static void main(String args[]){ for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+":"+i); if(i==5){ SecondThread st = new SecondThread(); new Thread(st,"新线程1").start(); new Thread(st,"新线程2").start(); } } }
程序的运行结果如下:
main:0
main:1
main:2
main:3
main:4
main:5
main:6
main:7
新线程2:0
新线程1:0
新线程2:1
main:8
新线程2:3
新线程1:2
新线程2:4
main:9
新线程2:6
新线程2:7
新线程1:5
新线程2:8
新线程1:9
结果分析:
从以上结果可以看出:新线程1和新线程2共享一个SecondThread对象,因此在执行run()方法时两个线程对象操纵的是同一个实例变量i。所以在执行输出的变量i的值是惟一的,例如新线程2:3、新线程1:2、新线程2:4,不会再出现新线程1:3或者新线程2:1等,且i值在逻辑上也是连续的,即i会从1到9由新线程1和新线程2交替惟一地输出,而实际顺序会不连续。因而可以得出以下结:采用实现Runnable接口的方法来创建线程类,多条线程可以共享同一个线程类(Runnable接口的实现类即target类)的实例属性。
注意:在使用继承Thread类时获得当前线程对象直接使用this就可以了,但是实现Runnable接口时要获得当前线程对象必须使用Thread.currentThread()方法。
若对上述程序作如下修改:
- SecondThread st1 = new SecondThread();
- SecondThread st2 = new SecondThread();
- new Thread(st1,"新线程1").start();
- new Thread(st2,"新线程2").start();
SecondThread st1 = new SecondThread(); SecondThread st2 = new SecondThread(); new Thread(st1,"新线程1").start(); new Thread(st2,"新线程2").start();
程序的运行结果如下:
main:0
main:1
main:2
main:3
main:4
main:5
main:6
main:7
新线程1:0
新线程2:0
新线程2:1
新线程1:1
main:8
main:9
新线程1:2
新线程1:3
新线程1:4
新线程2:2
新线程1:5
新线程2:3
新线程1:6
新线程2:4
新线程1:7
新线程2:5
新线程1:8
新线程2:6
新线程1:9
新线程2:7
新线程2:8
新线程2:9
结果分析:
从以上结果可以看出:新线程1和新线程2分别操纵不同的SecondThread对象的实例变量。
记住:Thread类本身也实现了Runnable接口,因此Thread类及其子类的对象也可以作为target传递给新的线程对象。
三、两种创建线程方式的比较
采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标(target)对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。
提示:在实际开发中,一般采用实现Runnable接口的方式来创建线程类,因为它具有更好的灵活性和可扩展性。
发表评论
-
java 参数传递
2012-06-22 13:00 0引用自:http://www.blogj ... -
log4j
2012-05-30 09:16 0Log4j配置详解 (2009-11-27 14: ... -
Commons-configuration设置读取属性文件
2012-05-14 13:02 0Commons-configuration-1.6设置属性 ... -
JAVA中关于静态(static)关键字的使用方法和内部类的调用 ,java基础
2011-07-03 18:54 0转载http://blog.csdn.net/xyf_84/a ... -
动态代理
2011-05-16 20:48 0(Dynamic Proxy)动态代理 ... -
Java中使用正则表达式
2011-05-01 17:08 0java正则表达式通过java.u ... -
初始化
2011-01-09 18:01 646引自:Thinking in Java 成员初始化:类 ... -
线程总结(线程的状态转换)
2010-12-17 15:09 644线程的状态转换:图片参照附件。 -
线程总结(sleep,join,yield,getPriority,setPriority,wait,notify,notifyAll)
2010-12-17 13:02 8451.sleep 是Thread的静态方法,publi ... -
线程总结(synchronized关键字)
2010-12-16 17:21 761一.Java的synchronized使用方法总结: 把sy ... -
java 静态初始化,动态初始化,以及构造器执行的顺序
2010-12-05 12:31 1398大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码 ... -
对象排序:Comparator与Comparable的区别
2010-05-25 17:45 1616当集合中存储的都是对象时,我们要对其进行排序,就要借助 ...
相关推荐
在MFC中,线程可以通过 `ResumeThread` 和 `SuspendThread` 方法实现启动和挂起: - **启动线程**:`ResumeThread` 使一个挂起状态的线程继续执行。 - **挂起线程**:`SuspendThread` 将正在运行的线程置于挂起状态...
线程创建和管理 线程创建和管理是多线程编程中一个非常重要的概念,在实际开发中,合理地创建和管理线程可以提高程序的效率和性能。在C#中,线程池和Thread类是两种常用的线程创建和管理方式。 一、线程池...
当一个线程被创建后,调用其`start()`方法将启动该线程,线程的执行体即`run()`方法内的代码将在新的线程中运行。 #### 示例代码解析 ```java class Hello extends Thread { public Hello(String name) { this....
总结一下,本主题涵盖了C#中的线程控制技术,包括线程的启动、暂停以及内存管理。理解这些概念对于编写高效、稳定的多线程应用程序至关重要。在实践中,应始终注意线程同步和内存管理的最佳实践,以避免可能出现的...
通过阅读源码,你可以了解到实际应用中的具体实现方式,包括线程创建、数据交换以及返回的逻辑。 总结,易语言线程返回数据的方法涉及到线程的创建、数据共享机制和同步策略等多个方面。开发者需要根据实际需求选择...
3. 易语言线程创建: 易语言提供了“创建线程”命令来创建新的线程。通常,我们需要定义一个函数(或子程序)作为线程的入口点,该函数将在新线程中运行。在类中,这个函数通常被声明为类的成员函数。 4. 类中启动...
`ExecutorService` 和 `Executors` 提供了一种高效地管理线程的方式,减少了线程创建和销毁的开销。 - **有返回值的线程** 通过 `Callable` 接口和 `Future` 类可以创建能够返回结果的线程。 - **锁** `...
首先说明Android的CPU分配的最小单元是线程,Handler一般是在某个线程里创建的,因而Handler和Thread就是相互绑定的,一一对应。 而Runnable是一个接口,Thread是Runnable的子类。所以说,他俩都算一个进程。 ...
本示例提供了一个简单的多线程应用,旨在帮助理解如何创建、启动和停止线程。以下将详细讲解相关知识点。 首先,我们讨论如何**创建多线程**。在Java中,有两种主要的方法来创建线程:通过继承Thread类或实现...
可以使用Thread类来创建新的线程,使用Start方法启动线程,使用Join方法等待线程结束。 在套接字通信中,多线程编程可以用于提高服务器端的并发处理能力。服务器端可以创建多个线程,每个线程负责处理一个客户端的...
通过理解多线程的基本概念,掌握易语言中的线程创建和管理方法,以及注意线程安全和同步,你可以编写出高效且稳定的多线程程序。在实际开发中,不断实践和优化,将是提升多线程编程能力的关键。
不同的线程创建方式都有其优缺,需要根据实际情况选择合适的线程创建方式。 本文主要介绍了Java使用Callable和Future创建线程操作的相关操作技巧与注意事项,为需要的朋友提供了有价值的参考。同时,本站还提供了更...
在易语言中,“启动线程”、“循环”和“延时”是三个重要的编程概念,它们在创建实时、响应式的程序中起到关键作用。 首先,我们要理解“启动线程”。在计算机编程中,线程是程序执行的最小单元,每个线程代表了...
线程池可以重用已存在的线程,减少了线程创建和销毁的开销。通过ThreadPool.QueueUserWorkItem方法,我们可以将任务添加到线程池中。 总结: 这个C# Winform项目展示了如何在运行时创建和关闭线程,以及如何安全地...
线程创建: 创建线程通常涉及以下步骤: 1. 定义线程类:创建一个新的类,继承自TThread。在类中,你可以定义私有变量、过程和函数,用于线程执行的具体逻辑。 2. 实现Create构造函数:在这个构造函数中,你可以初始...
线程池是一种多线程处理形式,它将线程和任务的概念分离开来,能够有效管理线程资源,减少线程创建和销毁的开销,提高程序性能。Java中可以通过Executors类快速创建线程池。 随着Java版本的更新,Java也引入了新的...
总结来说,在线程中启动进程是一种灵活的并发执行策略,结合多线程的快速响应和多进程的资源隔离,适用于需要大量并行计算的任务。同时,通过管道进行进程间通信,能够有效地传递和收集子进程的执行结果,为复杂系统...
总结起来,VS2019中的MFC线程创建涉及到创建自定义线程类、覆写关键成员函数、使用 `AfxBeginThread()` 创建线程以及进行线程同步。理解这些概念和实践,对于开发高效、稳定的多线程MFC应用至关重要。
C#.net 同步异步 SOCKET 通讯和多线程总结 本文旨在总结 C#.net 中的同步异步 SOCKET 通讯和多线程编程,涵盖服务端和客户端的实现细节。 一、服务端实现 服务端使用 System.Net 和 System.Net.Sockets 命名空间...
本文将深入探讨如何在VC++环境中实现线程的挂起、启动和恢复操作,这对于多线程编程至关重要。 首先,我们需要理解线程的状态。线程有三种基本状态:运行态(Running)、就绪态(Ready)和等待态(Blocked)。挂起...