1、继承Thread类,实现runable接口。
两种方式大家,众所周知
1.1、继承Thread类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ThreadTest extends Thread {
private static final Logger logger = LoggerFactory.getLogger(ThreadTest.class);
@Override
public void run() {
long id = ThreadTest.currentThread().getId();
String name = ThreadTest.currentThread().getName();
logger.info("id:"+id+",name:"+name);
}
}
public class MainTest {
public static void main(String[] args){
//继承Thread类
ThreadTest threadTest = new ThreadTest();
threadTest.start();
ThreadTest threadTest1 = new ThreadTest();
threadTest1.start();
ThreadTest threadTest2 = new ThreadTest();
threadTest2.start();
//实现runable接口方法
}
}
//结果
17:27:25.147 logback [Thread-1] INFO c.x.j.e.LamTest.Thread.ThreadTest - id:13,name:Thread-1
17:27:25.147 logback [Thread-0] INFO c.x.j.e.LamTest.Thread.ThreadTest - id:12,name:Thread-0
17:27:25.147 logback [Thread-2] INFO c.x.j.e.LamTest.Thread.ThreadTest - id:14,name:Thread-2
1.2、实现runable接口
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RunnableTest implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(Runnable.class);
@Override
public void run() {
long id = ThreadTest.currentThread().getId();
String name = ThreadTest.currentThread().getName();
logger.info("RunableTest: id: "+id+",name: "+name);
}
}
public class MainTest {
public static void main(String[] args){
//继承Thread类
/* ThreadTest threadTest = new ThreadTest();
threadTest.start();
ThreadTest threadTest1 = new ThreadTest();
threadTest1.start();
ThreadTest threadTest2 = new ThreadTest();
threadTest2.start();*/
//实现runable接口方法
RunnableTest runnableTest = new RunnableTest();
Thread thread = new Thread(runnableTest);
thread.start();
Thread thread1 = new Thread(runnableTest);
thread1.start();
Thread thread2 = new Thread(runnableTest);
thread2.start();
}
}
//结果
17:43:02.904 logback [Thread-1] INFO java.lang.Runnable - RunableTest: id: 13,name: Thread-1
17:43:02.904 logback [Thread-2] INFO java.lang.Runnable - RunableTest: id: 14,name: Thread-2
17:43:02.904 logback [Thread-0] INFO java.lang.Runnable - RunableTest: id: 12,name: Thread-0
2、基于线程池
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorSerivceTest { private static final Logger logger = LoggerFactory.getLogger(ExecutorSerivceTest.class); public void test(){ int n = 3; ExecutorService executorSerivce = Executors.newFixedThreadPool(n); int i =0; while (i<n){ executorSerivce.execute(new Runnable(){ @Override public void run() { long id = ThreadTest.currentThread().getId(); String name = ThreadTest.currentThread().getName(); logger.info("ExecutorSerivceTest:id:"+id+",name:"+name); } }); ++i; } } }
public class MainTest { public static void main(String[] args){ //继承Thread类 /* ThreadTest threadTest = new ThreadTest(); threadTest.start(); ThreadTest threadTest1 = new ThreadTest(); threadTest1.start(); ThreadTest threadTest2 = new ThreadTest(); threadTest2.start();*/ //实现runable接口方法 /* RunnableTest runnableTest = new RunnableTest(); Thread thread = new Thread(runnableTest); thread.start(); Thread thread1 = new Thread(runnableTest); thread1.start(); Thread thread2 = new Thread(runnableTest); thread2.start();*/ ExecutorSerivceTest executorSerivceTest = new ExecutorSerivceTest(); executorSerivceTest.test(); } } 10:44:57.656 logback [pool-2-thread-1] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - ExecutorSerivceTest:id:12,name:pool-2-thread-1 10:44:57.659 logback [pool-2-thread-2] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - ExecutorSerivceTest:id:13,name:pool-2-thread-2 10:44:57.660 logback [pool-2-thread-3] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - ExecutorSerivceTest:id:14,name:pool-2-thread-3
3、基于线程池有几种不同的形式
3.1、普通线程池
普通线程池上面的例子,上面是无返回值的线程池。
3.1.1、有返回值线程池
public void test2(String str){
int n = 3;
ExecutorService pool = Executors.newFixedThreadPool(n);
//创建多个又返回值的任务
List<Future> list = new ArrayList<Future>();
for(int i = 0;i<n;i++){
Callable c = new MyCallable(str);
//执行任务并获取future对象;
Future future = pool.submit(c);
list.add(future);
}
//关闭线程池
pool.shutdown();
//获取所有并发任务的返回值
for(Future f:list){
//从future对象上获取返回值的结果;
try {
logger.info("获取返回值:"+f.get()==null? "":f.get().toString());
} catch (InterruptedException e) {
logger.error("获取返回值异常:",e);
} catch (ExecutionException e) {
logger.error("获取返回值异常:",e);
}
}
}
//
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
private String param;
public MyCallable(String str) {
this.param = str;
}
@Override
public Object call() throws Exception {
Thread thread = Thread.currentThread();
return param.concat(":id:"+thread.getId()+",name:"+thread.getName());
}
}
17:03:33.767 logback [main] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 这是入参:id:12,name:pool-2-thread-1
17:03:33.771 logback [main] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 这是入参:id:13,name:pool-2-thread-2
17:03:33.771 logback [main] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 这是入参:id:14,name:pool-2-thread-3
3.1.2、无返回值线程池
public void test(){
int n = 3;
ExecutorService executorSerivce = Executors.newFixedThreadPool(n);
int i =0;
while (i<n){
executorSerivce.execute(new Runnable(){
@Override
public void run() {
long id = ThreadTest.currentThread().getId();
String name = ThreadTest.currentThread().getName();
logger.info("ExecutorSerivceTest:id:"+id+",name:"+name);
}
});
++i;
}
}
3.1.3、对比
大家可以看到有无返回值主要有三大区别
1、有返回值调用的是.submit()方法,而无返回值调用的是.execute()方法,打开源码如下
/** 有返回值
* Submits a value-returning task for execution and returns a
* Future representing the pending results of the task. The
* Future's {@code get} method will return the task's result upon
* successful completion.
*
* <p>
* If you would like to immediately block waiting
* for a task, you can use constructions of the form
* {@code result = exec.submit(aCallable).get();}
*
* <p>Note: The {@link Executors} class includes a set of methods
* that can convert some other common closure-like objects,
* for example, {@link java.security.PrivilegedAction} to
* {@link Callable} form so they can be submitted.
*
* @param task the task to submit
* @param <T> the type of the task's result
* @return a Future representing pending completion of the task
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if the task is null
*/
<T> Future<T> submit(Callable<T> task);
/** 无返回值
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
2、借用Callable对象,Callable需要实现一个call方法,并返回结果,这是是函数式编程,我们也可以写成lambda表达式形式,源码如下:
//
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
private String param;
public MyCallable(String str) {
this.param = str;
}
@Override
public Object call() throws Exception {
Thread thread = Thread.currentThread();
return param.concat(":id:"+thread.getId()+",name:"+thread.getName());
}
}
3、submit方法返回Future<T>类型
Future的理解我建议参考这篇文章
3.2、延迟执行线程池
public void scheduledExecutorService(String string){
int n =3;
ExecutorService executorService = Executors.newScheduledThreadPool(3);
for(int i=0;i<n;i++){
ScheduledFuture future = ((ScheduledExecutorService) executorService).schedule(new Runnable() {
@Override
public void run() {
logger.info("测试定时线程池:"+string);
long id = ThreadTest.currentThread().getId();
String name = ThreadTest.currentThread().getName();
logger.info("ExecutorSerivceTest:id:"+id+",name:"+name);
}
}, 10000, TimeUnit.MILLISECONDS);
}
ScheduledFuture future = ((ScheduledExecutorService) executorService).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
logger.info("测试定时线程池,第一个线程延迟1秒执行,剩下线程延迟10秒执行:"+string);
long id = ThreadTest.currentThread().getId();
String name = ThreadTest.currentThread().getName();
logger.info("ExecutorSerivceTest:id:"+id+",name:"+name);
}
}, 1000, 10000,TimeUnit.MILLISECONDS);
return;
}
17:35:51.128 logback [pool-2-thread-1] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 测试定时线程池,第一个线程延迟1秒执行,剩下线程延迟10秒执行:这是入参
17:35:51.132 logback [pool-2-thread-1] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - ExecutorSerivceTest:id:12,name:pool-2-thread-1
17:36:00.126 logback [pool-2-thread-1] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 测试定时线程池:这是入参
17:36:00.126 logback [pool-2-thread-3] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 测试定时线程池:这是入参
17:36:00.127 logback [pool-2-thread-2] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 测试定时线程池:这是入参
17:36:00.127 logback [pool-2-thread-1] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - ExecutorSerivceTest:id:12,name:pool-2-thread-1
17:36:00.127 logback [pool-2-thread-2] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - ExecutorSerivceTest:id:13,name:pool-2-thread-2
17:36:00.130 logback [pool-2-thread-3] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - ExecutorSerivceTest:id:14,name:pool-2-thread-3
17:36:01.127 logback [pool-2-thread-1] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 测试定时线程池,第一个线程延迟1秒执行,剩下线程延迟10秒执行:这是入参
17:36:01.127 logback [pool-2-thread-1] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - ExecutorSerivceTest:id:12,name:pool-2-thread-1
延迟线程使用
((ScheduledExecutorService) executorService).scheduleAtFixedRate这个方法实现
3.3、缓存线程池
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("缓存线程池:"+string);
System.out.println("cacheExecutorService: id: "+Thread.currentThread().getId()+",name:"+Thread.currentThread().getName());
}
});
缓存线程池:cacheExecutorService
cacheExecutorService: id: 12,name:pool-2-thread-1
缓存线程池是使用ExecutorService executorService = Executors.newCachedThreadPool();
3.4、单例线程池
public void singleExecutorService(String string){
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
@Override
public void run() {
logger.info("单例线程池无返回值:"+string);
logger.info("singleExecutorService: id: "+Thread.currentThread().getId()+",name:"+Thread.currentThread().getName());
}
});
Future future = executorService.submit(new MyCallable(string));
executorService.shutdown();
try {
logger.info("单例线程池有返回值:"+future.get().toString());;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
17:40:21.070 logback [pool-2-thread-1] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 单例线程池无返回值:singleExecutorService
17:40:21.073 logback [pool-2-thread-1] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - singleExecutorService: id: 12,name:pool-2-thread-1
17:40:21.074 logback [main] INFO c.x.j.e.L.Thread.ExecutorSerivceTest - 单例线程池有返回值:singleExecutorService:id:12,name:pool-2-thread-1
单例线程池是ExecutorService executorService = Executors.newSingleThreadExecutor();