解决Java多线程中11个常见问题
- 格式:docx
- 大小:26.21 KB
- 文档页数:6
解决常见Java技术问题的实用方法Java作为一种广泛使用的编程语言,常常会遇到一些技术问题。
本文将介绍一些解决常见Java技术问题的实用方法,帮助读者更好地应对挑战。
一、内存溢出问题的解决方法内存溢出是Java开发中常见的问题之一。
当程序运行时,如果申请的内存超过了Java虚拟机所允许的最大内存限制,就会导致内存溢出。
解决内存溢出问题的方法主要有以下几点:1. 检查代码中是否存在无限循环或递归调用,这些情况很容易导致内存溢出。
可以通过添加合适的终止条件或限制递归深度来解决这个问题。
2. 检查是否有未关闭的资源,比如数据库连接、文件流等。
如果资源未正确关闭,会导致内存泄漏,最终引发内存溢出。
使用try-with-resources语句或手动关闭资源可以解决这个问题。
3. 调整Java虚拟机的堆内存大小。
可以通过修改JVM参数中的-Xms和-Xmx来增加堆内存的大小,从而减少内存溢出的可能性。
二、线程同步问题的解决方法在多线程编程中,线程同步是一个常见的问题。
如果多个线程同时访问共享资源,可能会导致数据不一致或竞态条件。
解决线程同步问题的方法如下:1. 使用synchronized关键字来保护共享资源的访问。
通过在方法或代码块中添加synchronized关键字,可以确保同一时间只有一个线程能够访问共享资源,从而避免数据不一致的问题。
2. 使用Lock接口和Condition接口来实现显式锁。
相比于synchronized关键字,显式锁提供了更灵活的锁定和解锁方式,可以更好地控制线程的同步。
3. 使用线程安全的数据结构和类。
Java提供了一些线程安全的数据结构和类,如ConcurrentHashMap、CopyOnWriteArrayList等,它们在多线程环境下能够提供安全的操作。
三、性能优化问题的解决方法性能优化是Java开发中的重要问题,合理地优化程序可以提升系统的响应速度和资源利用率。
以下是一些常见的性能优化方法:1. 使用合适的数据结构和算法。
java线程安全问题原因及解决办法1.为什么会出现线程安全问题计算机系统资源分配的单位为进程,同⼀个进程中允许多个线程并发执⾏,并且多个线程会共享进程范围内的资源:例如内存地址。
当多个线程并发访问同⼀个内存地址并且内存地址保存的值是可变的时候可能会发⽣线程安全问题,因此需要内存数据共享机制来保证线程安全问题。
对应到java服务来说,在虚拟中的共享内存地址是java的堆内存,⽐如以下程序中线程安全问题:public class ThreadUnsafeDemo {private static final ExecutorService EXECUTOR_SERVICE;static {EXECUTOR_SERVICE = new ThreadPoolExecutor(100, 100, 1000 * 10,TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(100), new ThreadFactory() {private AtomicLong atomicLong = new AtomicLong(1);@Overridepublic Thread newThread(Runnable r) {return new Thread(r, "Thread-Safe-Thread-" + atomicLong.getAndIncrement());}});}public static void main(String[] args) throws Exception {Map<String, Integer> params = new HashMap<>();List<Future> futureList = new ArrayList<>(100);for (int i = 0; i < 100; i++) {futureList.add(EXECUTOR_SERVICE.submit(new CacheOpTask(params)));}for (Future future : futureList) {System.out.println("Future result:" + future.get());}System.out.println(params);}private static class CacheOpTask implements Callable<Integer> {private Map<String, Integer> params;CacheOpTask(Map<String, Integer> params) {this.params = params;}@Overridepublic Integer call() {for (int i = 0; i < 100; i++) {int count = params.getOrDefault("count", 0);params.put("count", ++count);}return params.get("count");}}}创建100个task,每个task对map中的元素累加100此,程序执⾏结果为:{count=9846}⽽预期的正确结果为:{count=10000}⾄于出现这种问题的原因,下⾯会具体分析。
Java语言程序调试技巧与多线程问题分析Java是一门跨平台、面向对象、速度快、安全稳定且易维护的编程语言。
Java语言在实际开发中有着广泛的应用,因为它具有良好的可扩展性。
进一步提升应用程序的可扩展性,Java支持多线程模式,但这也容易带来多线程问题,特别是在调试时遇到。
因此,我们需要一些Java语言程序调试技巧和多线程问题分析方法。
本篇文章将介绍一些实用的技巧,以帮助您更好地调试Java程序和解决多线程问题。
一、Java语言程序调试技巧1.使用断点在Java开发中,你无论使用哪个IDE,如Eclipse或IntelliJ IDEA,断点都是很有用的。
设置断点后,程序会停在这里,你可以检查代码、变量和其他内容。
设置断点是最基本的调试技巧,非常有用。
2.调试输出在Java开发中,输出语句是最常用的调试技巧之一。
使用System.out.println()或日志框架,输出你需要的信息。
这样你就可以在控制台或日志文件中查看值和其他信息。
3.代码跟踪在调试中,跟踪代码是非常重要的。
快速检查方法在哪里被调用,或在哪里引发异常,将以更高的精度帮助你识别问题所在。
如果你使用的IDE没有内置的跟踪工具,则可以使用Trace工具。
4.检查Java核心文件当Java程序崩溃时,最好检查异常堆栈跟踪。
异常堆栈可以告诉你哪一部分代码可能正在造成问题。
在Java中,每个线程都有自己的堆栈,你可以查看各个线程的堆栈以查找问题。
5.监视代码执行使用调试器时,一些IDE提供了一个非常有用的功能,即监视代码的执行。
单步执行,防止跳转,网络延迟,或其他情况可能与代码相关而不直接与代码上的错误相关。
6.代码截断当你需要在程序运行时改变代码的行为时,代码截断是一项非常有用的技术。
截断意味着你可以在代码中插入条件语句,以改变代码的执行路径。
这有助于识别问题的根源。
在Java中,截断可以使用断点和条件断点实现。
二、多线程问题分析Java中的多线程模式是提高应用程序性能的一个主要方式,但也容易导致多线程问题。
JAVA多线程的使用场景与注意事项总结Java多线程是指在一个程序中同时运行多个线程,每个线程都有自己的执行代码,但是又共享同一片内存空间和其他系统资源。
多线程的使用场景和注意事项是我们在开发中需要关注的重点,下面将详细进行总结。
一、Java多线程的使用场景:1.提高程序的执行效率:多线程可以充分利用系统资源,将一些耗时的操作放到一个线程中执行,避免阻塞主线程,提高程序的执行效率。
2.实现并行计算:多线程可以将任务拆分成多个子任务,每个子任务分配给一个线程来执行,从而实现并行计算,提高计算速度。
3.响应性能提升:多线程可以提高程序的响应性能,比如在用户界面的开发中,可以使用多线程来处理用户的输入和操作,保证界面的流畅性和及时响应。
4.实时性要求高:多线程可以实现实时性要求高的任务,比如监控系统、实时数据处理等。
5.任务调度与资源管理:多线程可以实现任务的调度和资源的管理,通过线程池可以更好地掌控任务的执行情况和使用系统资源。
二、Java多线程的注意事项:1.线程安全性:多线程操作共享资源时,要注意线程安全问题。
可以通过使用锁、同步方法、同步块等方式来解决线程安全问题。
2.死锁:多线程中存在死锁问题,即多个线程相互等待对方释放资源,导致程序无法继续执行。
要避免死锁问题,应尽量减少同步块的嵌套和锁的使用。
3.内存泄漏:多线程中存在内存泄漏问题,即线程结束后,线程的资源没有得到释放,导致内存占用过高。
要避免内存泄漏问题,应及时释放线程资源。
4.上下文切换:多线程的切换会带来上下文切换的开销,影响程序的执行效率。
要注意合理分配线程的数量,避免过多线程的切换。
5. 线程同步与通信:多线程之间需要进行同步和通信,以保证线程之间的正确协调和数据的一致性。
可以使用synchronized关键字、wait(和notify(方法等方式进行线程同步和通信。
6.线程池的使用:在多线程编程中,可以使用线程池来管理线程的创建和销毁,可以减少线程的创建和销毁的开销,提高程序的性能。
多线程常见⾯试题及答案1、如何在Java中实现线程(4种)?1.继承Thread类,重写run⽅法(其实Thread类本⾝也实现了Runnable接⼝)2.实现Runnable接⼝,重写run⽅法3.实现Callable接⼝,重写call⽅法(有返回值)4.使⽤线程池(有返回值)2、在具体多线程编程实践中,如何选⽤Runnable还是Thread?Java中实现多线程有两种⽅法:继承Thread类、实现Runnable接⼝,在程序开发中只要是多线程,肯定永远以实现Runnable接⼝为主,因为实现Runnable接⼝相⽐继承Thread类有如下优势:1、可以避免由于Java的单继承特性⽽带来的局限;2、增强程序的健壮性,代码能够被多个线程共享,代码与数据是独⽴的;适合多个相同程序代码的线程区处理同⼀资源的情况。
3、Thread类中的start()和run()⽅法有什么区别?start()⽅法来启动线程,真正实现了多线程运⾏,这时⽆需等待run⽅法体代码执⾏完毕⽽直接继续执⾏下⾯的代码:通过调⽤Thread类的start()⽅法来启动⼀个线程,这时此线程是处于就绪状态,并没有运⾏。
然后通过此Thread类调⽤⽅法run()来完成其运⾏操作的,这⾥⽅法run()称为线程体,它包含了要执⾏的这个线程的内容,Run⽅法运⾏结束,此线程终⽌,⽽CPU再运⾏其它线程。
run()⽅法当作普通⽅法的⽅式调⽤,程序还是要顺序执⾏,还是要等待run⽅法体执⾏完毕后才可继续执⾏下⾯的代码:⽽如果直接⽤run⽅法,这只是调⽤⼀个⽅法⽽已,程序中依然只有主线程–这⼀个线程,其程序执⾏路径还是只有⼀条,这样就没有达到多线程的⽬的。
4、Java中Runnable和Callable有什么不同相同点:1. 两者都是接⼝;(废话)2. 两者都可⽤来编写多线程程序;3. 两者都需要调⽤Thread.start()启动线程;不同点:1. 两者最⼤的不同点是:实现Callable接⼝的任务线程能返回执⾏结果;⽽实现Runnable接⼝的任务线程不能返回结果;2. Callable接⼝的call()⽅法允许抛出异常;⽽Runnable接⼝的run()⽅法的异常只能在内部消化,不能继续上抛;注意点:Callable接⼝⽀持返回执⾏结果,此时需要调⽤FutureTask.get()⽅法实现,此⽅法会阻塞主线程直到获取‘将来’结果;当不调⽤此⽅法时,主线程不会阻塞!5、如何避免死锁?1. 加锁顺序按照顺序加锁是⼀种有效的死锁预防机制。
15个Java多线程面试题及答案1)现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉。
这个多线程问题比较简单,可以用join方法实现。
2)在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它?lock接口在多线程和并发编程中最大的优势是它们为读和写分别提供了锁,它能满足你写像ConcurrentHashMap这样的高性能数据结构和有条件的阻塞。
Java线程面试的问题越来越会根据面试者的回答来提问。
芯学苑老师强烈建议在你在面试之前认真读一下Locks,因为当前其大量用于构建电子交易终统的客户端缓存和交易连接空间。
3)在java中wait和sleep方法的不同?通常会在电话面试中经常被问到的Java线程面试问题。
最大的不同是在等待时wait会释放锁,而sleep一直持有锁。
Wait通常被用于线程间交互,sleep通常被用于暂停执行。
4)用Java实现阻塞队列。
这是一个相对艰难的多线程面试问题,它能达到很多的目的。
第一,它可以检测侯选者是否能实际的用Java线程写程序;第二,可以检测侯选者对并发场景的理解,并且你可以根据这个问很多问题。
如果他用wait()和notify()方法来实现阻塞队列,你可以要求他用最新的Java 5中的并发类来再写一次。
5)用Java写代码来解决生产者——消费者问题。
与上面的问题很类似,但这个问题更经典,有些时候面试都会问下面的问题。
在Java中怎么解决生产者——消费者问题,当然有很多解决方法,我已经分享了一种用阻塞队列实现的方法。
有些时候他们甚至会问怎么实现哲学家进餐问题。
6)用Java编程一个会导致死锁的程序,你将怎么解决?这是我最喜欢的Java线程面试问题,因为即使死锁问题在写多线程并发程序时非常普遍,但是很多侯选者并不能写deadlock free code(无死锁代码?),他们很挣扎。
关于Java程序员面试中的多线程问题总结很多核心Java面试题多线程(Multi-Threading)和集合框架(CollectionsFramework),理解核心线程概念时,娴熟的实际经验是必需的。
这篇文章收集了Java线程方面一些典型的问题,这些问题经常被高级工程师所问到。
0、Java中多线程同步是什么?在多线程程序下,同步能控制对共享资源的访问。
如果没有同步,当一个Java线程在修改一个共享变量时,另外一个线程正在使用或者更新同一个变量,这样容易导致程序出现错误的结果。
1、解释实现多线程的几种方法?一Java线程可以实现Runnable接口或者继承Thread类来实现,当你打算多重继承时,优先选择实现Runnable。
2、Thread.start()与Thread.run()有什么区别?Thread.start()方法(native)启动线程,使之进入就绪状态,当cpu分配时间该线程时,由JVM调度执行run()方法。
3、为什么需要run()和start()方法,我们可以只用run()方法来完成任务吗?我们需要run()&start()这两个方法是因为JVM创建一个单独的线程不同于普通方法的调用,所以这项工作由线程的start方法来完成,start由本地方法实现,需要显示地被调用,使用这俩个方法的另外一个好处是任何一个对象都可以作为线程运行,只要实现了Runnable接口,这就避免因继承了Thread类而造成的Java的多继承问题。
4、什么是ThreadLocal类,怎么使用它?ThreadLocal是一个线程级别的局部变量,并非“本地线程”。
ThreadLocal为每个使用该变量的线程提供了一个独立的变量副本,每个线程修改副本时不影响其它线程对象的副本(译者注)。
下面是线程局部变量(ThreadLocalvariables)的关键点:一个线程局部变量(ThreadLocalvariables)为每个线程方便地提供了一个单独的变量。
Java多线程习题知识点:Java的多线程,实现多线程的两种方法,线程控制、调度方法一、选择题1、什么原因可导致线程停止执行。
()A.线程调用了 wait()方法;B.线程调用了yield()方法;C.线程调用了 pause()方法;D.线程调用了 sleep() 方法。
2、哪个方法是实现Runnable接口所需的?A.wait() B.run() C.stop() D.update() E.resume() 3、以下代码的调试结果为?()public class Bground extends Thread{public static void main(String argv[]){Bground b = new Bground();b。
run();}public void start(){for (int i = 0; i <10; i++){System。
out.println("Value of i = " + i);}}}A.编译错误,没有定义线程的run方法;B.由于没有定义线程的run方法,而出现运行错误;C。
编译通过,运行输出 values 0 to 9D。
编译通过,运行无输出4、有关线程的叙述正确的有:()A.通过继承Thread类或实现Runnable接口,可以获得对类中方法的互斥锁定.B. 可以获得对任何对象的互斥锁定。
C。
线程通过调用对象的synchronized 方法可取得对象的互斥锁定。
D。
线程调度算法是平台独立的。
5、以下哪个是线程类的方法?A.yield()B. sleep(long msec)C。
go()D。
stop()6、以下哪个最准确描述synchronized关键字?A.允许两线程并行运行,而且互相通信;B. 保证在某时刻只有一个线程可访问方法或对象;C。
保证允许两个或更多处理同时开始和结束;D. 保证两个或更多线程同时开始和结束.7、于Java语言的内存回收机制,下列选项中最正确的一项是( )。
Java技术常见错误及解决方法Java作为一种广泛应用的编程语言,被广大开发者广泛使用。
然而,即使是经验丰富的开发者也会遇到一些常见的错误。
在本文中,我将介绍一些常见的Java 技术错误,并提供解决方法,帮助开发者更好地应对这些问题。
1. 空指针异常(NullPointerException)空指针异常是Java开发中最常见的错误之一。
它通常发生在试图调用一个空对象的方法或访问一个空对象的属性时。
为了避免这个错误,我们可以在使用对象之前先进行非空判断。
使用if语句或者使用Optional类来处理可能为空的对象是一个不错的选择。
2. 类型转换异常(ClassCastException)类型转换异常通常发生在试图将一个对象转换为不兼容的类型时。
为了避免这个错误,我们应该在进行类型转换之前使用instanceof运算符进行类型检查。
如果对象不是目标类型的实例,就不应该进行类型转换。
3. 数组越界异常(ArrayIndexOutOfBoundsException)数组越界异常发生在试图访问数组中不存在的索引时。
为了避免这个错误,我们需要确保在访问数组元素之前,索引值在合法范围内。
可以使用条件语句或循环来检查索引值是否越界。
4. 方法重载错误方法重载错误通常发生在两个或多个方法具有相同的名称和参数列表,但返回类型不同。
为了避免这个错误,我们需要确保方法的签名(包括参数类型和返回类型)是唯一的。
可以通过改变方法名称或者参数列表来解决这个问题。
5. 死锁(Deadlock)死锁是多线程编程中常见的错误。
它发生在两个或多个线程相互等待对方释放资源的情况下。
为了避免死锁,我们可以使用同步块和锁来控制对共享资源的访问。
此外,使用线程池和避免嵌套锁也是避免死锁的有效方法。
6. 内存泄漏(Memory Leak)内存泄漏是指应该被回收的内存没有被释放的情况。
这通常发生在长时间运行的应用程序中。
为了避免内存泄漏,我们应该及时释放不再使用的对象和资源。
让每一名学员高薪就业 www.itsource.cn 解决Java多线程中11个常见问题 1、线程是什么? 简单来说,线程是进程中独立运行的子任务。 2、创建线程的方式 方式一:将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法 方式二:声明实现 Runnable 接口的类。该类然后实现 run 方法 推荐方式二,因为接口方式比继承方式更灵活,也减少程序间的耦合。 3、获取当前线程信息? Thread.currentThread() 4、线程的分类 线程分为守护线程、用户线程。线程初始化默认为用户线程。 setDaemon(true) 将该线程标记为守护线程或用户线程。 特性:设置守护线程,会作为进程的守护者,如果进程内没有其他非守护线程,那么守护线程也会被销毁,即使可能线程内没有运行结束。 5、线程的生命周期 线程是一个动态执行的过程,它也有一个从产生到死亡的过程。生命周期的五种状态: 新建(new Thread):当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。 例如:Thread t1=new Thread(); 就绪(runnable):线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start(); 运行(running):线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。 死亡(dead):当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。 堵塞(blocked):由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。 6、线程间的关系? 某线程a 中启动另外一个线程 t,那么我们称 线程 t是 线程a 的一个子线程,而 线程a 是 线程t 的 父线程。 最典型的就是我们在main方法中 启动 一个 线程去执行。其中main方法隐含的main线程为父线程。 7、线程API一览:如何启动、停止、暂停、恢复线程? (1)start() 使线程处于就绪状态,Java虚拟机会调用该线程的run方法; (2)stop() 停止线程,已过时,存在不安全性,原因如下: 一是可能请理性的工作得不得完成; 二是可能对锁定的对象进行“解锁”,导致数据不同步不一致的情况。 推荐 使用 interrupt() +抛异常 中断线程。 (3)yield() 线程礼让, 放弃当前线程的CPU资源。放弃时间不确认,也有可能刚刚放弃又获得CPU资源。 (4)t.join() 正在执行t.join()语句的线程等待t线程运行完终止。 让每一名学员高薪就业 www.itsource.cn 8、synchronized关键字用法 一 原子性(互斥性):实现多线程的同步机制,使得锁内代码的运行必需先获得对应的锁,运行完后自动释放对应的锁。 二 内存可见性:在同一锁情况下,synchronized锁内代码保证变量的可见性。 三 可重入性:当一个线程获取一个对象的锁,再次请求该对象的锁时是可以再次获取该对象的锁的。 如果在synchronized锁内发生异常,锁会被释放。 总结: (1)synchronized方法 与 synchronized(this) 代码块 锁定的都是当前对象,不同的只是同步代码的范围 (2)synchronized (非this对象x) 将对象x本身作为“对象监视器”: a、多个线程同时执行 synchronized(x) 代码块,呈现同步效果。 b、当其他线程同时执行对象x里面的 synchronized方法时,呈现同步效果。 c、当其他线程同时执行对象x里面的 synchronized(this)方法时,呈现同步效果。 (3)静态synchronized方法 与 synchronized(calss)代码块 锁定的都是Class锁。Class 锁与 对象锁 不是同一个锁,两者同时使用情况可能呈异步效果。 (4)尽量不使用 synchronized(string),是因为string的实际锁为string的常量池对象,多个值相同的string对象可能持有同一个锁。 9、ReentrantLock的使用 一个简单的示例: private java.util.concurrent.locks.Lock lock = new ReentrantLock(); public void method() { try { lock.lock(); //获取到锁lock,同步块 } finally { lock.unlock();//释放锁lock } } ReentrantLock 比 synchronized 功能更强大,主要体现: (1)ReentrantLock 具有公平策略的选择。 (2)ReentrantLock 可以在获取锁的时候,可有条件性地获取,可以设置等待时间,很有效地避免死锁。 如 tryLock() 和 tryLock(long timeout, TimeUnit unit) (3)ReentrantLock 可以获取锁的各种信息,用于监控锁的各种状态。 (4)ReentrantLock 可以灵活实现多路通知,即Condition的运用。 10、线程间的通信方式 线程间通信的方式主要为共享内存、线程同步。 线程同步除了synchronized互斥同步外,也可以使用wait/notify实现等待、通知的机制。 (1)wait/notify属于Object类的方法,但wait和notify方法调用,必须获取对象的对象级别锁,即synchronized同步方法或同步块中使用。 (2)wait()方法:在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,或者其他某个线程中断当前线程,导致当前线程一直阻塞等待。等同wait(0)方法。 让每一名学员高薪就业 www.itsource.cn wait(long timeout) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。 单位为毫秒。 void wait(long timeout, int nanos) 与 wait(long timeout) 不同的是增加了额外的纳秒级别,更精细的等待时间控制。 (3)notfiy方法:唤醒在此对象监视器上等待的单个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。 (4)notifyAll方法:唤醒在此对象监视器上等待的所有线程。 需要:wait被执行后,会自动释放锁,而notify被执行后,锁没有立刻释放,由synchronized同步块结束时释放。
应用场景:简单的生产、消费问题。 synchronized (lock) {//获取到对象锁lock try { lock.wait();//等待通信信号, 释放对象锁lock } catch (InterruptedException e) { e.printStackTrace(); } //接到通信信号 } synchronized (lock) {//获取到对象锁lock lock.notify();//通知并唤醒某个正等待的线程 //其他操作 } //释放对象锁lock
11、Executors框架(线程池)的使用 (1)线程池是什么? 线程池是一种多线程的处理方式,利用已有线程对象继续服务新的任务(按照一定的执行策略),而不是频繁地创建销毁线程对象,由此提供服务的吞吐能力,减少CPU的闲置时间。具体组成部分包括: a、线程池管理器(ThreadPool)用于创建和管理线程池,包括创建线程池、销毁线程池,添加新任务。 b、工作线程(Worker)线程池中的线程,闲置的时候处于等待状态,可以循环回收利用。 c、任务接口(Task)每个任务必须实现的接口类,为工作线程提供调用,主要规定了任务的入口、任务完成的收尾工作、任务的状态。 d、等待队列(Queue)存放等待处理的任务,提供缓冲机制。 (2)Executors框架常见的执行策略 Executors框架提供了一些便利的执行策略。 java.util.concurrent.ExecutorService service = java.util.concurrent.Executors.newFixedThreadPool(100); - newSingleThreadExecutor:创建一个单线程的线程池。 这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的 让每一名学员高薪就业 www.itsource.cn 线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。 - newFixedThreadPool:创建固定大小的线程池。 每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。 - newCachedThreadPool:创建一个可缓存的线程池。 如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。 - newScheduledThreadPool:创建一个大小无限的线程池。 此线程池支持定时以及周期性执行任务的需求。 - newSingleThreadScheduledExecutor:创建一个单线程的线程池。 此线程池支持定时以及周期性执行任务的需求。 (3)ExecutorService线程池管理 ExecutorService的生命周期有3个状态:运行、关闭(shutting down)、停止。 提交任务submit(xxx)扩展了基本方法 Executor.execute(java.lang.Runnable)。 Future submit(Callable task) 提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。 Future submit(Runnable task) 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。 Future submit(Runnable task, T result) 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。 shutdown() 启动一次顺序关闭,执行以前提交的任务,但不接受新任务。 List shutdownNow() 试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。 一个简单的示例: public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 100; i++) { executorService.submit(new Runnable() { @Override public void run() { System.out.println("哈哈"); } }); } /** * 如果不再需要新任务,请适当关闭executorService并拒绝新任务 */ executorService.shutdown(); } (3)ThreadPoolExecutor机制