多线程
Java中共有三种多线程的实现方式,实现多线程主要有两种途径:
- 继承Tread类
- 实现Runable接口(Callable接口)
继承Thread类
Tread类是一个支持多线程的功能类,只要有一个子类它就可以实现多线程的功能。
class MyThread extends Thread {
public void run() {
//线程主体操作
}
}
public class TestMain {
public static void main(String[] args) {
MyThread mt1 = new MyTread();
mt1.start(); //不是调用run()方法!!!
MyThread mt2 = new MyTread();
mt2.start()
}
}
run()方法是线程的主体操作方法,而多线程启动调用的是start()方法。
但如果某一个线程对象重复进行了启动,那么会抛出“IllegalThreadStateException”异常。
为什么要使用start()方法来启动线程?
使用Thread类的start()方法不仅仅要启动多线程的执行代码,还要根据不同的操作系统进行资源分配。
实现Runnable接口
虽然Thread类可以实现多线程的主体类定义,但Java只能够单继承,所以为了解决单继承的限制,所以提供了Runnable接口。它是FunctionalInterface接口(函数式接口),所以只包含有一个方法。
public interface Runnable {
public void run();
}
使用方法与继承Thread方式基本类似,都是将主体操作防止在run()方法中,但有有一个严重的区别:Runnable接口中并没有start()方法的实现,所以想要启动多线程一定得依靠Thread类完成。
在Thread类中有如下构造方法:
public Thread(Runnable target)
所以代码应该如下:
class MyTread implements Runnable{
public void run() {
//线程主体操作
}
}
public class TestMain {
public static void main(String[] args) {
MyThread mt1 = new MyTread();
new Thread(mt1).start(); //启动多线程
new Thread(mt1).start();
}
}
利用Runnable接口,我们可以使多个线程对象都直接占用了同一个MyThread对象引用,即多个线程对象都直接访问同一个数据资源,即实现了数据共享。
多线程两种实现方式的区别?
首先使用Runnable接口与Thread类相比,解决了单继承的局限,所以如果要使用,一定使用Runnable接口。
- Thread类是Runnable接口的子类,使用Runnable接口实现多线程可以避免单继承局限。
- Runnable有着更好的数据共享。
Callabel
虽然Runnable接口实现的多线程不能返回操作结果,所以Callable接口的出现就是为了解决这一矛盾。它包含在java.util.concurrent.Callable包中。
public interface Callable<V> {
public V call() throw Exception;
}
使用方式:
class MyTread implements Callable<String>{
private int ticket = 10;
public String call() {
for(int i = 0; i < 100; i++) {
if(this.ticket > 0) {
System.out.println("卖票!ticket = " + this.ticket--);
}
}
return "票卖光了!";
}
}
public class TestMain {
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyTread mt1 = new MyTread();
MyTread mt2 = new MyTread();
//FutureTask是Runnable接口子类,所以可以使用Thread类的构造来接受task对象
FutureTask<String> task1 = new FutureTask<String>(mt1);
FutureTask<String> task2 = new FutureTask<String>(mt2);
//启动多线程
new Thread(task1).start();
new Thread(task2).start();
//多线程执行完毕后,开一通过FutrueTask的父接口Future中的get()方法完成
System.out.println("A线程的返回结果 = " + task1.get());
System.out.println("A线程的返回结果 = " + task2.get());
}
}
Thread类里没有直接支持Callable接口的多线程应用。而在java.util.concurrent.FutureTask类中有提供对Callable接口对象的操作。在FutureTask类里面定义有如下的构造方法:
public FutureTask(Callable<V> callable)
所以我们可以通过FutreTask对象取得线程的返回值。