Java 实现多线程两种方法及其区别与联系

Java中实现多线程操作有两种方法:

1.继承Thread类;
如覆写Thread类中的run方法;
举例:

class MyThread extends Thread{
    	private String name;
    	public MyThread(String name) {
    		super();
    		this.name = name;
    	}
    	public void run() {
    		for (int i=0;i<3;i++) {
    			System.out.println(name+"运行,   i="+i);
    		}
    	}
    }
    public class Threads {
    	public static void main(String[] args) {
    		MyThread mt1=new MyThread("A");
    		MyThread mt2=new MyThread("B");
    		mt1.run();
    		mt2.run();
    	}
    }

输出结果:

A运行,   i=0
A运行,   i=1
A运行,   i=2
B运行,   i=0
B运行,   i=1
B运行,   i=2

输出结果可以看出,A与B是两个不同的进程,线程A先于B执行;如何实现A,B线程的同时进行、即多线程?
如果将最后的“mt1.run();mt2.run();”改为“mt1.start();mt2.start();”,多次执行后其中一组结果:

B运行,   i=0
A运行,   i=0
A运行,   i=1
A运行,   i=2
B运行,   i=1
B运行,   i=2

比较两组结果发现:现在两个线程对象是交错运行,即哪个对象抢到了CPU,哪个就先运行,此处的start()方法,调用的是run()方法定义的主体,Thread类的每个对象只能调用一次start()方法;

2.实现Runnable接口;
首先明白接口是由全局变量和抽象方法构成,且访问权限均为public;
Runnable()接口只定义了一个抽象方法,即:public void run();
举例:

class myth  implements Runnable{
	private String name;
	public myth(String name) {
		super();
		this.name = name;
	}
	public void run() {
		for (int i=0;i<3;i++) {
			System.out.println(name+"运行,   i="+i);
		}
	}
}
public class testone{
	public static void main(String[] args) {
		myth mt1=new myth("A");
		myth mt2=new myth("B");
		Thread t1=new Thread(mt1);
		Thread t2=new Thread(mt2);
		t1.start();
		t2.start();		
	}
}

输出结果:

A运行,   i=0
B运行,   i=0
B运行,   i=1
B运行,   i=2
A运行,   i=1
A运行,   i=2

此处的运行机制与Thread类中法start()方法一致,但Runnable()接口没有start()方法的定义,所以需要依靠Thread类完成,Thread类中提供了可以接受Runnable接口的子类实例对象的构造方法:

public Thread(Runnable target);
public Thread(Runnable target,String name);

Thread类中提供了可以接受Runnable的子类实例对象的构造方法,明白了两者之间的联系、两种实现多线程的方法之间存在什么区别呢?

通过一个例子来看一下:
1.继承Thread类:

class MyThreads  extends Thread{
	private int ticket=5;
	public void run() {
		for (int i=0;i<100;i++) {
			if(ticket>0) {
			System.out.println("买票:ticket="+ticket--);
		}
	}
		}
	}
public class ticket {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyThreads m1=new MyThreads();
		MyThreads m2=new MyThreads();
		MyThreads m3=new MyThreads();
		m1.start();
		m2.start();
		m3.start();	
	}
}

输出结果:

买票:ticket=5
买票:ticket=5
买票:ticket=4
买票:ticket=3
买票:ticket=2
买票:ticket=1
买票:ticket=5
买票:ticket=4
买票:ticket=4
买票:ticket=3
买票:ticket=3
买票:ticket=2
买票:ticket=1
买票:ticket=2
买票:ticket=1

2.实现Runnable接口:

class MyThreads  implements Runnable{
	private int ticket=5;
	public void run() {
		for (int i=0;i<100;i++) {
			if(ticket>0) {
			System.out.println("买票:ticket="+ticket--);
		}
	}
		}
}
public class ticket {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyThreads m1=new MyThreads();
		new Thread(m1).start();
		new Thread(m1).start();
		new Thread(m1).start();		
	}
}

输出结果:

买票:ticket=5
买票:ticket=4
买票:ticket=3
买票:ticket=1
买票:ticket=2

比较实例输出结果,继承Thread类出现了票数总数的错误,而Runnable接口并没有出现,说明Runnable接口比Thread类在多线程共享资源更利于实现,可以得出,一个类继承了Thread类,则不适用于多线程共享资源,而实现Runnable接口,就更方便实现资源的共享;

实现Runnable接口相对于Thread类来说,有以下优势:

1.适合多个相同程序代码的线程去处理同一资源的情况;
2.可以避免由于Java的单继承特性带来的局限;
3.增强了程序的健壮性,代码能够被多个线程共享,代码与数据独立;