Thread类实现
Thread类本质是实现了Runnable接口的一个实例,代表一个线程的实例。
启动线程
通过Thread类的start()实例方法。
start()方法是一个native方法,它将启动一个新的线程,并执行run()方法,就可以启动新线程并执行自己定义的run()方法
优缺点
优点:代码简单
缺点:该类无法继承别的类
代码实现‘
public class NewThread extends Thread {
private String name;
public NewThread(String name){
this.name = name;
}
public void run(){
for(int i = 0; i < 5; i++){
System.out.println(name+"运行:"+i);
try {
sleep((long) (Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
NewThread mTh1 = new NewThread("a");
NewThread mTh2 = new NewThread("b");
mTh1.start();
mTh2.start();
}
ab线程交替运行
public class NewRunnable implements Runnable {
private String title;
public NewRunnable(String title) {
this.title = title;
}
@Override
public void run() { // 线程的主方法
for (int x = 0; x < 10; x++) {
System.out.println(this.title + "运行,x = " + x);
}
}
}
public static void main(String[] args) {
NewRunnable myThread1 = new NewRunnable("A");
NewRunnable myThread2 = new NewRunnable("B");
new Thread(myThread1).start();
new Thread(myThread2).start();
}
要启动多线程依靠Thread类的start()方法完成
实现的是Runnable接口,没有这个方法可以继承
需要依靠Thread类中的 一个构造方法:public Thread(Runnable target),来接收Runnable接口对象
优缺点
优点:继承其他类,统一实现该接口的实例可以共享资源
缺点:代码复杂
public class NewCallable implements Callable<Integer> {
private String name;
public NewCallable(String name){
this.name = name;
}
@Override
public Integer call() throws Exception {
int sum = 0 ;
for (int i = 0; i <= 100; i++){
System.out.println(name +"线程:"+i);
sum +=i;
}
return sum;
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class MainTest {
public static void main(String[] args) {
NewCallable th1 = new NewCallable("A");
NewCallable th2 = new NewCallable("B");
//1.执行callable方式,需要futureTask实现类的支持,用于接受运算结果
FutureTask<Integer> result1 = new FutureTask<>(th1);
FutureTask<Integer> result2 = new FutureTask<>(th2);
new Thread(result1).start();
new Thread(result2).start();
Integer sum;
try {
sum = result1.get();
System.out.println("-----------");
System.out.println(sum);
sum = result2.get();
System.out.println("-----------");
System.out.println(sum);
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
线程池,其实就是一个容纳多个线程的容器,其中的线程可以重复使用,省去了频繁创建对象的操作,因为反复创建线程是非常消耗资源的
线程池是线程工厂创建线程的,默认采用 DefaultThreadFactory ,它会给线程池创建的线程设置一些默认值,比如:线程的名字、是否是守护线程,以及线程的优先级等。
本质通过 new Thread() 创建线程的 ,只不过这里的构造函数传入的参数要多一些,由此可以看出通过线程池创建线程并没有脱离最开始的那两种基本的创建方式,还是通过 new Thread() 实现的。
优点:实现自动化装配,易于管理,循环利用资源
定时器Timer
class TimerThread extends Thread {
// TODO
}
定时器也可以实现线程,如果新建一个 Timer,令其每隔 10 秒或设置两个小时之后,执行一些任务,那么这时它确实也创建了线程并执行了任务。
本质上有一个继承自 Thread 类的 TimerThread,所以定时器创建线程最后又绕回到最开始说的两种方式。
匿名内部类创建线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}).start();
new Thread(() -> System.out.println(Thread.currentThread().getName())).start();
}
匿名内部类或 lambda 表达式创建线程仅仅是在语法层面上实现了线程,匿名内部类实现线程仅仅是用一个匿名内部类把需要传入的 Runnable 给实例出来。
1.启动线程需要调用 start() 方法,而start() 方法调用 run() 方法,源码中 target 实际上就是一个 Runnable,即使用 Runnable 接口实现线程时传给Thread类的对象。
private Runnable target;
//Thread中的run方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
运行内容主要来自于两个地方,要么来自于 target,要么来自于重写的 run() 方法,
实现线程只有一种方式,而要想实现线程执行的内容,却有两种方式,① 可以通过 实现 Runnable 接口的方式,②继承 Thread 类重写 run() 方法的方式,把想要执行的代码传入,让线程去执行。
为什么说实现 Runnable 接口比继承 Thread 类实现线程要好
代码的架构
Runnable 里只有一个 run() 方法,它定义了需要执行的内容,在这种情况下,实现了 Runnable 与 Thread 类的解耦,Thread 类负责线程启动和属性设置等内容,权责分明。
某些情况下可以提高性能
继承 Thread 类方式,每执行一次任务,都需要新建一个独立的线程,执行完任务后线程走到生命周期的尽头被销毁,如果此时执行的内容比较少(只是在 run() 方法里简单打印一行文字),那么它所带来的开销并不大,相比于整个线程从开始创建到执行完毕被销毁,这一系列的操作比 run() 方法打印文字本身带来的开销要大得多。
如果我们使用实现 Runnable 接口的方式,就可以把任务直接传入线程池,使用一些固定的线程来完成任务,不需要每次新建销毁线程,大大降低了性能开销。
Java 语言不支持双继承
如果类一旦继承了 Thread 类,那么它后续就没有办法再继承其他的类,限制了代码未来的可拓展性。
源码:
public interface Runnable {
//返回值为void且没有声明抛出任何异常
public abstract void run();
}
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
//声明了 throws Exception 和 V 泛型的返回值,
V call() throws Exception;
}