多线程java实现代码_Java多线程的4种实现⽅式
Java有四种实现多线程的⽅式:
1).继承Thread类
2).实现Runnable接⼝
3).实现Callable接⼝
4).使⽤线程池
前三种实现⽅式的代码:
1 public classMultiThread {
2 //继承Thread类
3 static class MyThread1 extendsThread{
4 @Override
5 public voidrun() {6
System.out.println(Thread.currentThread().getName()+": extends Thread⽅式");7 }8 }9 //实现Runnable接⼝
10 static class MyThread2 implementsRunnable{11 @Override12 public voidrun() {13
System.out.println(Thread.currentThread().getName()+": implements Runnable⽅式");14 }15 }16 //实现Callable接⼝
17 static class MyThread3 implements Callable{18 @Override19 public String call() throwsException {20 return
Thread.currentThread().getName()+": implements Callable⽅式";21 }22 }23
24 public static void main(String[] args) throwsException{25 Thread thread1 = newMyThread1();26 Thread thread2 = new Thread(newMyThread2());27 FutureTask futureTask = new FutureTask<>(newMyThread3());28 Thread thread3 = newThread(futureTask);29
30 thread1.start();31 thread2.start();32 thread3.start();33 System.out.());34 }35 }
运⾏结果:
Thread-0: extendsThread⽅式
Thread-1: implementsRunnable⽅式
Thread-2: implements Callable⽅式
line26,27⾏当传⼊⼀个Runnable target参数给Thread后,Thread的run()⽅法就会调⽤target.run(),参考Thread类部分源代码:
public class Thread implements Runnable {
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
1.继承Thread本质上也是实现Runnable接⼝。
2.实现Callable接⼝的任务线程能返回执⾏结果,⽽实现Runnable接⼝的线程不能返回结果
3.使⽤Callable的⽅式时候需要⽤FutureTask<>进⾏包装(适配),FutureTask实现了Runnable和Future,通过future⾥⾯的get()⽅法来得到返回值。需要注意的是get()⽅法是阻塞的,就是说取不到值会使主线程⼀直等待。
4.⽣产中⼏乎都会使⽤线程池。
线程池:⽤来控制运⾏的线程的数量,处理过程中将任务放⼊等待队列,然后在线程创建后启动这些
任务。如果线程数量超过了最⼤数量(maximumPoolSize),超出数量的线程将会在等待队列排队等候。如果等待队列已满,再进来的任务就会按照拒绝策略拒绝。
线程池的特点:线程复⽤,控制最⼤并发数,管理线程。
线程池的优势:
1.降低资源消耗,通过复⽤线程来降低创建和销毁线程的消耗。
2.提⾼响应速度,当任务到达时不需要等待创建线程。
3.提⾼线程的可管理性,使⽤线程池可以进⾏统⼀的分配,监控和调优。
java⾃带的线程池的实现:
//固定数量线程的线程池
ExecutorService threadPool1 =wFixedThreadPool(cpuNum);//⼀个线程的线程池
ExecutorService threadPool2 =wSingleThreadExecutor();//多个线程的线程池
ExecutorService threadPool3 =wCachedThreadPool();//Java8新特性 ExecutorService threadPool3 = wWorkStealingPool();
上⾯⼏线程池的底层都是ThreadPoolExecutor(),ThreadPoolExecutor是线程池的核⼼类。ThreadPoolExecutor的构造器最多有7个可配参数:
ThreadPoolExecutor的7个参数:
corePoolSize:核⼼池的⼤⼩,这个参数跟后⾯讲述的线程池的实现原理有⾮常⼤的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,⽽是等待有任务到来才创建线程去执⾏任务,除⾮调⽤了prestartAllCoreThreads()或者prestartCoreThread()⽅法,从这2个⽅法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者⼀个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建⼀个线程去执⾏任务,当线程池中的线程数⽬达到corePoolSize后,就会把到达的任务放到缓存队列当中;
maximumPoolSize:线程池最⼤线程数,这个参数也是⼀个⾮常重要的参数,它表⽰在线程池中最多能创建多少个线程;
keepAliveTime:表⽰线程没有任务执⾏时最多保持多久时间会终⽌。默认情况下,只有当线程池中的线程数⼤于corePoolSize
时,keepAliveTime才会起作⽤,直到线程池中的线程数不⼤于corePoolSize,即当线程池中的线程数⼤于corePoolSize时,如果⼀个线程空闲的时间达到keepAliveTime,则会终⽌,直到线程池中的线程数不超过corePoolSize。但是如果调⽤了allowCoreThreadTimeOut(boolean)⽅法,在线程池中的线程数不⼤于corePoolSize时,keepAliveTime参数也会起作⽤,直到线程池中的线程数为0;
unit:参数keepAliveTime的时间单位,有7种取值:
TimeUnit.DAYS;//天
TimeUnit.HOURS;//⼩时
TimeUnit.MINUTES;//分钟
TimeUnit.SECONDS;//秒
TimeUnit.MILLISECONDS;//毫秒
TimeUnit.MICROSECONDS;//微妙
TimeUnit.NANOSECONDS;//纳秒
workQueue:⼀个阻塞队列,⽤来存储等待执⾏的任务,这个参数的选择也很重要,会对线程池的运⾏过程产⽣重⼤影响,⼀般来说,这⾥的阻塞队列有以下⼏种选择:ArrayBlockingQueue和PriorityBlockingQueue使⽤较少,⼀般使⽤LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
threadFactory:线程⼯⼚,主要⽤来创建线程;
java线程池创建的四种handler:表⽰当拒绝处理任务时的策略,有以下四种取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前⾯的任务,然后重新尝试执⾏任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调⽤线程处理该任务
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论