学习Java中的多线程编程系列(1):Thread和Runnable
Java编程时,为了提高程序运行的效率和处理速度,可以在一个程序中同时运行多个线程。
关于多线程有下面几个特性:
1)Java程序可同时并行运行多个相对独立的线程。例如创建一个线程来接收数据,另一个线程发送数据。
2)线程是相互独立,任何线程都不能访问除自身之外的其他线程的局部变量。
3)如果两个线程同时访问同一个方法,那每个线程将各自得到此方法的一个拷贝。
Java中线程的实现通常有两种方式:派生Thread类,并覆盖run方法;通过Runnable接口。
我们平时编程都是单线程,一个程序就是一个线程上运行。如下程序:
package testing; /*** * * @author Hadoop * * Implementation in only one thread * */ public class OnlyThread { /* * 单线程版本 */ public static void main(String[] args) { // TODO Auto-generated method stub run(); } public static void run() { /* * 输出直角三角形状 '*' */ for(int count = 1, row = 1; row < 10; row++, count++) { for(int i = 0; i < count; i++) { System.out.print('*'); } System.out.println(); } } }
学习了多线程编程之后,我们就可以通过派生Thread的方式或者Runnable接口的方式来操作。
方式一:派生Thread类
1)创建一个新的线程类,继承Thread类并覆盖Thread类的run()方法;
2)创建一个线程类的对象,创建方法与一般对象的创建相同,使用关键字new完成;
3)启动新线程对象,调用start()方法;
4)线程自己调用run()方法。
下面两个程序就是用派生Thread类的方式来实现多线程:
package testing; public class ThreadDemo1 extends Thread{ // 使用派生Thread类的方法实现多线程, //其中Thread类是一个通用的线程类:java.lang.Thread 可以不import /** * * @param args * * MAIN CLASS 单线程版本 */ ThreadDemo1() { // 无餐构造方法 } ThreadDemo1(String szName) { //带参构造方法 super(szName); // 调用父类的构造方法 } public void run() { // 覆盖Thread类中的run方法,注意不是重载 for(int count = 1, row = 1; row < 10; row++, count++) { for(int i = 0; i < count; i++) { System.out.print('*'); } System.out.println(); } } public static void main(String[] args) { // TODO Auto-generated method stub ThreadDemo1 td = new ThreadDemo1(); // 对象 td.start(); } }
运行结果:
*
**
***
****
*****
******
*******
********
*********
package testing; public class ThreadDemo2 extends Thread{ ThreadDemo2() { // 无餐构造方法 } ThreadDemo2(String szName) { //带参构造方法 super(szName); // 调用父类的构造方法 } public void run() { // 覆盖Thread类中的run方法,注意不是重载 for(int count = 1, row = 1; row < 10; row++, count++) { for(int i = 0; i < count; i++) { System.out.print('*'); } System.out.println(); } } public static void main(String[] args) { // TODO Auto-generated method stub ThreadDemo2 td1 = new ThreadDemo2(); ThreadDemo2 td2 = new ThreadDemo2(); ThreadDemo2 td3 = new ThreadDemo2(); td1.start(); td2.start(); td3.start(); } }
运行结果:
*
**
***
****
*****
******
*******
********
*********
*
**
***
****
*****
**
**
***
****
*****
******
*******
********
*********
*****
*******
********
*********
第二段程序的结果表明:线程并没有按照程序中调用的顺序来执行,而是产生了多个线程赛跑现象。
方式二:Runnable接口
1)创建一个实现Runnable接口的类,并且在这个类中重写run方法;
2)使用关键字new新建一个ThreadType的实例;
3)通过Runnable的实例创建一个线程对象,在创建线程对象时,调用的构造函数是new Thread(ThreadType),它用ThreadType中实现的run()方法作为新线程对象的run()方法;
4)通过调用ThreadType对象的start()方法启动线程运行。
程序如下:
package testing; public class ThreadDemo3 implements Runnable{ // 用Runnable接口的方式实现多线程 public void run() { // 重载run函数,这里是重载 for(int count = 1, row = 1; row < 10; row++, count++) { for(int i = 0; i < count; i++) { System.out.print('*'); } System.out.println(); } } public static void main(String[] args) { // TODO Auto-generated method stub Runnable rb1 = new ThreadDemo3(); // 对象 Runnable rb2 = new ThreadDemo3(); Runnable rb3 = new ThreadDemo3(); Thread td1 = new Thread(rb1); // 还要回到Thread类的调用中,只不过上面不再需要派生Thread类了 Thread td2 = new Thread(rb2); Thread td3 = new Thread(rb3); td1.start(); td2.start(); td3.start(); } }
需要注意的是,方式二也会出现线程赛跑的现象。
参考:
《Java从入门到精通》