Java多线程实现的方式有四种
1 继承Thread类,重写run方法
2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
3.通过Callable和FutureTask创建线程
4.通过线程池创建线程
具体实现
前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果 后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中
线程实现方式1:继承Thread类的线程实现方式如下:
1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target 3.通过Callable和FutureTask创建线程(future.get()接口会阻塞); 4.通过线程池创建线程
前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果 后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中
方式1:继承Thread类的线程实现方式如下:
package org.example.myThread;
public class ThreadDemo01 extends Thread {
public ThreadDemo01() {
//编写子类的构造方法,可缺省
}
public void run() {
//编写自己的线程代码
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
public static void main(String[] args) {
ThreadDemo01 thread01 = new ThreadDemo01();
ThreadDemo01 thread02 = new ThreadDemo01();
thread01.setName("自定义的线程1");
thread01.start();
thread02.setName("自定义的线程2");
thread02.start();
//main线程
System.out.println(Thread.currentThread().toString());
}
自定义的线程2 0
自定义的线程2 1
自定义的线程2 2
Thread[main,5,main]
自定义的线程1 0
自定义的线程1 1
自定义的线程1 2
}
线程实现方式2:通过实现Runnable接口,实现run方法,接口的实现类的实例作为Thread的target作为参数传入带参的Thread构造函数,通过调用start()方法启动线程
package org.example.myThread;
class MyThread implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 2; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
System.out.println(Thread.currentThread().getName() + "-->我是通过实现接口的线程实现方式!");
}
}
public class ThreadDemo02 {
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread());
t1.start();
//thread 2
new Thread(new MyThread()).start();
//main线程
System.out.println(Thread.currentThread().toString());
}
}
Thread-0 0
Thread-0 1
Thread-0-->我是通过实现接口的线程实现方式!
Thread[main,5,main]
Thread-1 0
Thread-1 1
Thread-1-->我是通过实现接口的线程实现方式!
线程实现方式3:通过Callable和FutureTask创建线程
a:创建Callable接口的实现类 ,并实现Call方法
b:创建Callable实现类的实现,使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值
c:使用FutureTask对象作为Thread对象的target创建并启动线程
d:调用FutureTask对象的get()来获取子线程执行结束的返回值
package org.example.myThread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class Tickets<Object> implements Callable<Integer> {
private int i;
public Tickets(int i) {
this.i = i;
}
public int myFun(int i) {
return i * 10;
}
//重写call方法
@Override
public Integer call() throws Exception {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + "-->我是通过实现Callable接口通过FutureTask包装器来实现的线程");
return myFun(i);
}
}
public class ThreadDemo03 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// TODO Auto-generated method stub
Callable<Integer> oneCallable = new Tickets<Object>(2);
FutureTask<Integer> oneTask = new FutureTask<Integer>(oneCallable);
Thread t = new Thread(oneTask);
t.start();
System.out.println(oneTask.get());
Callable<Integer> callable = new Tickets<Object>(3);
FutureTask<Integer> task = new FutureTask<Integer>(callable);
Thread t1 = new Thread(task);
t1.start();
System.out.println(task.get());
//main线程
System.out.println(Thread.currentThread().toString());
}
}
Thread-0-->我是通过实现Callable接口通过FutureTask包装器来实现的线程
20
Thread-1-->我是通过实现Callable接口通过FutureTask包装器来实现的线程
30
Thread[main,5,main]
}
ExecutorService、Callable都是属于Executor框架。返回结果的线程是在JDK1.5中引入的新特征,还有Future接口也是属于这个框架,有了这种特征得到返回值就很方便了。 通过分析可以知道,他同样也是实现了Callable接口,实现了Call方法,所以有返回值。这也就是正好符合了前面所说的两种分类
Callable<Integer> oneCallable = new Tickets<Object>(2);
FutureTask<Integer> oneTask = new FutureTask<Integer>(oneCallable);
Thread t = new Thread(oneTask);
t.start();
System.out.println(oneTask.get());
Callable<Integer> callable = new Tickets<Object>(3);
FutureTask<Integer> task = new FutureTask<Integer>(callable);
Thread t1 = new Thread(task);
t1.start();
System.out.println(task.get());
//main线程
System.out.println(Thread.currentThread().toString());
}
执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。get方法是阻塞的,即:线程无返回结果,get方法会一直等待。
线程实现方式4:通过线程池创建线程
创建线程池底层均会调用ThreadPoolExecutor构造函数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
corePoolSize:核心线程最大数量,通俗点来讲就是,线程池中常驻线程的最大数量。线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程;如果超过corePoolSize,则新建的是非核心线程。
maximumPoolSize:线程池中运行最大线程数(包括核心线程和非核心线程)
keepAliveTime:线程池中空闲线程(仅适用于非核心线程)所能存活的最长时间。当需要执行的任务很多,线程池的线程数大于核心池的大小时,keepAliveTime才起作用。
unit:存活时间单位,与keepAliveTime搭配使用(TimeUnit.DAYS,TimeUnit.HOURS,TimeUnit.MINUTES,TimeUnit.MILLISECONDS,TimeUnit.MICRODECONDS)
workQueue:存放任务的阻塞队列(维护着等待执行的 Runnable对象。当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务)。
handler:线程池饱和策略
线程池处理新提交任务流程
1.判断线程池中核心线程数是否已达阀值corePoolSize,若否,则创建一个新核心线程执行任务
2.若核心线程数已达阀值corePoolSize,判断阻塞队列workQueue是否已满,若未满,则将新任务添加进阻塞队列
3.若已满,判断线程池中线程数是否达到阀值maximumPoolSize,若否,则新建一个非核心线程执行任务。若达到阀值,则执行线程池饱和策略
java创建线程池的四种方式:
newCachedThreadPool 创建一个可缓存的线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收,则新建线程
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行
newSingleThreadExecutor 创建一个单线程化的线程池,它只会唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行
package org.example.myThread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadDemo05 {
private static int POOL_NUM = 5; //线程池数量
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < POOL_NUM; i++) {
RunnableThread thread = new RunnableThread();
Thread.sleep(100);
executorService.execute(thread);
}
//关闭线程池
executorService.shutdown();
}
}
class RunnableThread implements Runnable {
@Override
public void run() {
System.out.println("通过线程池方式创建的线程:" + Thread.currentThread().getName() + " ");
}
}
通过线程池方式创建的线程:pool-1-thread-1
通过线程池方式创建的线程:pool-1-thread-2
通过线程池方式创建的线程:pool-1-thread-3
通过线程池方式创建的线程:pool-1-thread-1
通过线程池方式创建的线程:pool-1-thread-2
}