多线程的实现方式:继承Thread类,实现Runable接口,实现Callable接口
1、继承Tread类:
public class MyThread extends Thread {
private int count = 1;
@Override
public void run() {
System.out.println("MyThread + " + Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
缺点:java是单继承的,如果MyThread还需要继承其他类,是无法继承的,另外count是线程的一个局部变量,如要在主线程中共享该变量的值是没法共享的
2、实现Runnable接口,Runnable本身只是一个接口,只有一个run()方法,需要将接口的实例传递给Thread及其子类才能实现一个线程
源码:
public class MyThreadRunnable implements Runnable {
private int count = 7;
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "---" + count);
for (int i = 0; i < 7; i++) {
System.out.println(Thread.currentThread().getName() + ":" + count--);
}
}
public static void main(String[] args) {
MyThreadRunnable runnable = new MyThreadRunnable();
Thread t1 = new Thread(runnable);
t1.setName("runnable1");
t1.start();
Thread t2 = new Thread(runnable);
t2.setName("runnable2");
t2.start();
}
}
优点:解决了java单继承的问题,变量可以共享,实际上是多个线程共享了Runnable接口的实例以及变量,所以多数时候使用线程都应该选择实现接口的方式
3、实现Callable接口,从源码上看,与Runnable接口的区别是有返回值,并且允许抛出异常
源码:
Callable接口需要借助FutureTask来实现线程,实际上实现Runnable接口的是FutureTask<>
public class MyThreadCallable implements Callable<String> {
private int count = 9;
@Override
public String call() throws Exception {
for (int i = 0; i < 9; i++) {
System.out.println("计数:" + count--);
}
return "count=" + count;
}
public static void main(String[] args) {
MyThreadCallable callable = new MyThreadCallable();
FutureTask<String> task = new FutureTask<>(callable);
Thread thread = new Thread(task);
thread.start();
//可以获取返回值和抛出异常
try {
String result = task.get();
System.out.println("获取返回值:" + result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
4、多线程执行的优先级问题,即线程抢占CPU执行的几率问题,有2种调度模型
分时调度模型:轮流获取cpu执行权,平均分配cpu的使用时间片
抢占式调度模型:优先级高的线程使用cpu的几率要高些,如果优先级一样,则随机选
java使用的是抢占式调度模型,通过设置优先级参数实现,优先级的int值范围1<priority<10,默认是5:设置优先级
thread.setPriority();
6、设置为守护线程thread.setDaemon();
守护线程和非守护线程:
当2个线程(一个守护线程,一个非守护线程)运行时,当非守护线程执行完毕,守护线程也没有必要继续运行
7、主线程和子线程
主线程:main函数执行的线程为主线程,在main函数里面创建的线程均为子线程,main函数是一个非守护线程(不能设置为守护线程),当主线程结束后,其他线程没有执行完,仍然可以继续运行:
主线程执行完毕,子线程仍然在等待