多线程的实现方式
1、继承Thread类
(1)定义一个类继承Thread,重写run()方法;
(2)创建Thread类的子类对象;
(3)调用start()开启新线程。
//主线程和自定义线程并发执行
public class thread {
public static void main(String[] args) {
//2、创建Thread类的子类对象
MyThread myThread = new MyThread();
//3、调用start()开启新线程
myThread.start();
for (int i = 0; i < 3000; i++) {
System.out.println("bb");
}
}
}
//1、定义一个类继承Thread,重写run()方法
class MyThread extends Thread{
public void run(){
for (int i = 0; i < 3000; i++) {
System.out.println("aaaaa");
}
}
}
2、实现Runnable接口
(1)定义类实现Runnable接口,重写run()方法;
(2)创建自定义的Runnable的子类对象;
(3)创建Thread对象,将Runnable当做参数传递给Thread的构造函数;
(4)调用start()开启新线程。
//主线程和自定义线程并发执行
public class thread {
public static void main(String[] args) {
//2、创建自定义的Runnable的子类对象
MyRunnable myRunnable = new MyRunnable();
//3、创建Thread对象,将Runnable当做参数传递给Thread的构造函数
Thread thread = new Thread(myRunnable);
//4、调用start()开启新线程
thread.start();
for (int i = 0; i < 3000; i++) {
System.out.println("bb");
}
}
}
//1、定义类实现Runnable接口,重写run()方法
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 3000; i++) {
System.out.println("aaaaa");
}
}
}
3、实现Callable接口
(1)定义类实现Callable接口,重写call()方法;
(2)创建Callable子类的实例化对象;
(3)创建FutureTask对象,并将Callable对象传入FutureTask的构造方法中;
(4)实例化Thread对象,并在构造方法中传入FutureTask对象;
(5)调用start()启动新线程。
//主线程和自定义线程并发执行
public class thread {
public static void main(String[] args) {
//2、创建Callable子类的实例化对象
MyCallable myCallable = new MyCallable();
//3、创建FutureTask对象,并将Callable对象传入FutureTask的构造方法中
FutureTask futureTask = new FutureTask<String>(myCallable);
//4、实例化Thread对象,并在构造方法中传入FutureTask对象
Thread thread = new Thread(futureTask);
//5、调用start()启动新线程
thread.start();
for (int i = 0; i < 3000; i++) {
System.out.println("bb");
}
}
}
//1、定义类实现Callable接口,重写call()方法
class MyCallable implements Callable{
@Override
public String call() throws Exception {
for (int i = 0; i < 3000; i++) {
System.out.println("aaaaaaaa");
}
return "0";
}
}
4、第1种,第2种和第3种的匿名内部类
5、基于线程池的方式
我们知道,线程和数据库连接这些资源都是非常宝贵的资源。那么每次需要的时候创建,不需要的时候销毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池。当然了,线程池也不需要我们来实现,jdk的官方也给我们提供了API。
public class CreateThreadDemo12_ThreadPool {
public static void main(String[] args) throws Exception {
// 创建固定大小的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
while (true) {
// 提交多个线程任务,并执行
threadPool.execute(new Runnable() {
@Override
public void run() {
printThreadInfo();
}
});
}
}
/**
* 输出当前线程的信息
*/
private static void printThreadInfo() {
System.out.println("当前运行的线程名为: " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
输出结果为:
当前运行的线程名为: pool-1-thread-1
当前运行的线程名为: pool-1-thread-2
当前运行的线程名为: pool-1-thread-4
当前运行的线程名为: pool-1-thread-3
当前运行的线程名为: pool-1-thread-7
当前运行的线程名为: pool-1-thread-8
当前运行的线程名为: pool-1-thread-9
当前运行的线程名为: pool-1-thread-6
当前运行的线程名为: pool-1-thread-5
当前运行的线程名为: pool-1-thread-10
继承Thread类和实现Runnable接口这两种方式的区别:
1、实现Runnable接口,可以避免单继承的局限性,具有较强的健壮性。
2、Runnable可以实现资源的共享,多个线程同时处理同一资源。
3、Thread类的线程间都是独立运行的,资源不共享。
4、继承Thread类不再被其他类继承。
实现Runnable接口和实现Callable接口这两种方式的区别:
1、Callable的核心是call()方法,允许返回值;Runnable的核心是run()方法,没有返回值。
2、call()方法可以抛出异常,但是run()方法不行。
3、Callable和Runnable都可以应用于executor是,而Thread类只支持Runnable。