多线程的创建方式:①继承Thread类②实现Runnable接口。第一种方式的最大局限就是不支持多继承,在JAVA中继承只能单根继承,所以为了实现多继承,可以实现Runnable接口的方式来实现。两者的创建的线程在工作时的性质是一样的。
继承Thread类
关于创建
自定义一个MyThread,继承Thread,并且重写run方法;创建一个MyThread 类的对象,通过此对象来进行调用start()。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread");
}
}
public class Run {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
System.out.println("运行结束");
}
}
运行结果如下,MyThread.java中的run方法执行的比较晚,说明使用多线程时,代码的运行结果与代码的执行顺序是无关的。线程是一个子任务,CPU随机执行调用线程中的run,所以就会出现先打印“运行结束”,后输出“MyThread”这样的结果。
- .start()方法的作用:①启动当前线程 ②调用当前线程的 run()
两个问题:
- 通过调用 run() 方法是不会开辟新的线程的 ,执行的线程还是 调用 run() 的线程。所以不能通过调用run() 的方式来进行启动线程。
- 在启动一个线程,不能让已经启动 start() 的线程去执行,,会报出IllegalThreadStateException错误。争取的的做法应该是在重新创建一个对象,来进行新的 start()。
关于 Thread类 的方法
- void start(): 启动线程,并执行对象中的run() 方法
- run() :通常徐亚重写Thread 类中的方法,将创建的线程要执行的操作声明在此方法中
- String getName() :返回线程的名称。
- void setName() : 设置该线程的名称。
- static Thread currentThread() :返回当前线程。在Thread 子类中就是this,通常用于主线程和Runnable实现类。
- yield() :线程让步,暂停当前正在执行的线程,把执行机会让给优先级相同或者更好的线程。若队列中没有同优先级的线程,忽略此方法。
- join() :当某个程序中执流中调用了其他线程的join方法,调用线程将被阻塞,知道 join() 方法加入的 join线程执行完为止。
- sleep() : 当前线程“睡眠”指定的millitme 毫秒 ,在指定的时间内,当前线程阻塞状态。
实现Runnab接口
关于创建
创建线程的另外一种方式是实现Runnable接口。步骤如下
①创建一个实现Runnable接口的类
②实现类去实现Runnable中的抽象方法:run()
③创建实现类的对象 ,将此对象作为参数传递到Thread类中的构造器中,创建Thread类的对象
④通过Thread类的对象来调用start()
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("运行中");
}
}
public class Run {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
System.out.println("运行结束!");
}
}
关于 Thread 和 Runnable
- 开发中优先使用Runnable 接口中的方式
- 原因:①实现方式没有类的单继承性的局限性②实现的方式更适合多线程有共享数据的情况。
实际上Thread也是实现Runnable 接口的类。
实现Callable接口
关于创建
- 创建一个实现 Callable 接口的实现类
- 实现call() 方法,将此线程需要执行的操作声明在call方法中,允许有返回值
- 创建一个实现Callable接口的是实现类对象
- 将实现类对象作为参数传递到 FutureTask 构造器中,创建FutureTask的对象。
- 如果第二步没有参数,则将FutureTaskd的对象作为参数传递到Thread类构造器中,创建Tread对象,并调用start()
- 如果第二步返回参数(需要获取Callable中的call方法中的返回值),使用get()。get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyCallable implements Callable{
@Override
public Object call() throws Exception {
int sum = 0;
for(int i = 1;i <= 100;i++){
if(i % 2 == 0){
System.out.println(i);
sum += i;
}
}
return sum;
}
}
public class Test {
public static void main(String[] args) {
MyCallable num = new MyCallable();
FutureTask futureTask = new FutureTask(num);
new Thread(futureTask).start();
try {
//get() 返回值为FutureTask 构造器Callable 实现类重写call的返回值
Object o = futureTask.get();
System.out.println(o);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
实现Runnable 和实现Callable
- call() 可以有返回值
- call()还可以跑出异常,被外面的操作捕获,接收异常的信息。
- 可以支持泛型
使用线程池
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中,可以避免频繁创建销毁,实现重复利用。
好处:
- 提高响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中的线程,不需要每次都进行创建)
- 便于线程管理
- corePoolSize:核心池中的大小
- maximumPoolSize:最大的线程数
- keepAliveTime: 线程没有任务时最多保持多长时间会终止
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyRunnable implements Runnable {
@Override
public void run() {
for(int i = 1;i <= 100;i++){
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}}
}
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 1;
for(int i = 1;i <= 100;i++){
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName()+i);
sum += i;
}
}
return sum;
}
}
public class Pool {
public static void main(String[] args) {
//1.提供指定线程数量的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
//2.执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
//service.execute(new MyRunnable());//适合适用于Runnable
service.submit(new MyCallable());//适合使用与Callable
//3.关闭线程池
service.shutdown();
}
}
有关于线程池的API ExextorService 和 Exectors
- ExextorService :真正的线程池接口,常见的子类有ThreadPoolExecutor
- void execute(Runnable command):执行任务/命令,没有返回值,易班用来执行Runnable
- Future submit (Callable task) :执行任务,有返回值,一般用来执行Callable
- void shutdown :关闭连接池 - Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
- Executors.newCachedThreadPool():创建一个课根据需要创建新线程的线程池
- Executors.newFixedThreadddPool():创建一个可重用固定线程数的线程池
- Executors.newSingleThreadExecutor():创建一个只有一个线程的线程池
- Executors.newScheduledThreadPool(n):创建一个线程池,它可以安排在给定延迟后运行命令或者定期的执行。