java多线程编程
- 格式:pdf
- 大小:75.40 KB
- 文档页数:28
java juc详解Java JUC(Java Util Concurrent)是Java编程语言的一个扩展库,用于实现多线程并发编程。
JUC库提供了一系列的工具类和接口,用于解决多线程编程中的一些常见问题,如线程安全、并发控制、线程间通信等。
在多线程编程中,线程的安全性是一个重要的问题。
线程安全性指的是多个线程同时访问一个共享资源时,不会引发任何问题。
JUC 提供了一些线程安全的数据结构,如ConcurrentHashMap、ConcurrentLinkedQueue等。
这些数据结构在内部使用了锁和CAS(Compare and Swap)等机制来保证线程安全性。
除了线程安全性,JUC还提供了一些并发控制的机制。
例如,Semaphore可以用来控制同时访问某个资源的线程数量;CountDownLatch可以用来实现线程的等待,直到某个条件满足后才继续执行;CyclicBarrier可以用来实现线程的同步,多个线程在达到某个屏障点之前都会被阻塞等待。
线程间的通信也是多线程编程中的一个重要问题。
JUC提供了一些用于线程间通信的机制,如BlockingQueue和Exchanger。
BlockingQueue是一个阻塞队列,多个线程可以通过它来进行数据的交换。
Exchanger则是一个用于两个线程之间交换数据的工具类。
除了上述的工具类和接口,JUC还提供了一些常用的并发执行框架。
例如,Executor框架可以用来管理和调度多个线程的执行;Fork/Join框架可以用来实现任务的拆分和合并,以实现并行计算;并发集合类则可以用来管理和操作一组共享的数据。
JUC库的设计目标是提供高效、可扩展和易用的多线程编程工具。
在实现上,JUC库使用了一些高级的并发控制技术,如锁、条件变量、信号量等。
这些技术可以有效地提高多线程程序的性能和可靠性。
总结来说,Java JUC是Java编程语言的一个扩展库,用于实现多线程并发编程。
多线程并发的书籍以下是多线程并发的相关书籍:1. 《Java多线程编程核心技术》:这本书比较基础,写的比较细,代码示例比较多,包含了线程的基础使用、线程锁的使用(Synchronized和ReentrantLock)、单例模式、定时任务、线程组的相关概念,可以当做工具书来看,缺点就是没有深入底层的实现原理。
2. 《JAVA并发编程:核心方法与框架》:这本书和上一本书是同一个作者写的,所以风格很相似,代码示例比较多,主要介绍了juc包下的各类并发框架的使用,包括CountDownLatch、线程池、Futura、ForkJoin、并发队列等,书中介绍了很多API的使用方式,建议当做工具书使用,缺点是没有深入底层的实现原理。
3. 《Java并发编程实战》:这本书是外国人写的,介绍了Java并发编程的各种算法和实现方式,有点难度。
4. 《多处理器编程的艺术》:这本书介绍了并发编程的各种算法和实现方式,包括Java实现,有点难度。
5. 《并发的艺术》:这本书介绍了多核处理器的共享内存模型中的各种算法和实现方式。
6. 《Java虚拟机并发编程》:这本书介绍了JVM平台上各种语言的并发比较,如Java、Scala、Clojure等。
7. 《实战Java高并发程序设计》:这本书介绍了Java高并发程序设计的实战技巧和经验。
8. 《七周七并发模型》:这本书介绍了七种并发模型的比较和实现方式。
9. 《Go并发编程实战》:这本书介绍了Go语言中的并发编程实现方式。
10. 《事务信息系统》:这本书从数据库层面介绍了并发编程的实现方式。
11. 《C并发编程经典实例》:这本书介绍了C语言中的并发编程实现方式。
12. 《C++ Concurrency in Action》:这本书介绍了C++中的并发编程实现方式。
13. 《Python编程实战:运用设计模式、并发和程序库创建高质量程序》:这本书介绍了Python中并发编程的实现方式。
Java多线程详解——⼀篇⽂章搞懂Java多线程⽬录1. 基本概念程序(program)程序是为完成特定任务、⽤某种语⾔编写的⼀组指令的集合。
即指⼀段静态的代码(还没有运⾏起来),静态对象。
进程(process)进程是程序的⼀次执⾏过程,也就是说程序运⾏起来了,加载到了内存中,并占⽤了cpu的资源。
这是⼀个动态的过程:有⾃⾝的产⽣、存在和消亡的过程,这也是进程的⽣命周期。
进程是系统资源分配的单位,系统在运⾏时会为每个进程分配不同的内存区域。
线程(thread)进程可进⼀步细化为线程,是⼀个程序内部的执⾏路径。
若⼀个进程同⼀时间并⾏执⾏多个线程,那么这个进程就是⽀持多线程的。
线程是cpu调度和执⾏的单位,每个线程拥有独⽴的运⾏栈和程序计数器(pc),线程切换的开销⼩。
⼀个进程中的多个线程共享相同的内存单元/内存地址空间——》他们从同⼀堆中分配对象,可以访问相同的变量和对象。
这就使得相乘间通信更简便、搞笑。
但索格线程操作共享的系统资源可能就会带来安全隐患(隐患为到底哪个线程操作这个数据,可能⼀个线程正在操作这个数据,有⼀个线程也来操作了这个数据v)。
配合JVM内存结构了解(只做了解即可)class⽂件会通过类加载器加载到内存空间。
其中内存区域中每个线程都会有虚拟机栈和程序计数器。
每个进程都会有⼀个⽅法区和堆,多个线程共享同⼀进程下的⽅法区和堆。
CPU单核和多核的理解单核的CPU是⼀种假的多线程,因为在⼀个时间单元内,也只能执⾏⼀个线程的任务。
同时间段内有多个线程需要CPU去运⾏时,CPU也只能交替去执⾏多个线程中的⼀个线程,但是由于其执⾏速度特别快,因此感觉不出来。
多核的CPU才能更好的发挥多线程的效率。
对于Java应⽤程序java.exe来讲,⾄少会存在三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。
如过发⽣异常时会影响主线程。
Java线程的分类:⽤户线程和守护线程Java的gc()垃圾回收线程就是⼀个守护线程守护线程是⽤来服务⽤户线程的,通过在start()⽅法前调⽤thread.setDaemon(true)可以吧⼀个⽤户线程变成⼀个守护线程。
Java语言多线程技术应用研究作者:林铁瀛来源:《科技创新导报》2011年第11期摘要:多线程编程是Java语言的一个很重要的特点,它是面向对象程序设计的关键技术之一。
本文简要的探讨了Java语言多线程的基本技术,就线程的创建、线程控制和调度及线程同步等处理技术做了相关探讨。
关键词:多线程创建控制同步应用中图分类号:G633.3 文献标识码:A 文章编号:1674-098X(2011)04(b)-0022-01多线程程序是Java语言的一个很重要的特点,在一个Java程序中,可以同时并行运行多个相对独立的线程。
线程是一段完成某个特定功能的语句体,一个线程是一个程序内部单个顺序的控制流。
多线程是指同一个应用程序中,有多个顺序流同时执行,即多线程表示一个程序内部可以同时执行多个线程。
多线程的程序能更好地表述和解决现实世界的问题,是计算机应用开发和设计过程的一个必然发展趋势。
1 线程的创建在Java程序设计中,创建线程有两种方法:一个方法是从一个自定义的类(如Mythread)中创建,即让程序继承Thread类。
例如:Thread t=new Mythread();这个类扩展了Java基础类库中的Thread类及其方法。
Mythread类中必须替换Thread类中的run()方法。
应注意的是,初始化Mythread为类,并不能使对象t作为一个线程开始执行,而必须独立运行的子语句体放到run()方法(是Thread类中的一个方法)中。
再调用线程的star()方法来开始线程的执行,进而依顺序调用run()方法。
这种创建线程的方法有一个缺陷,即必须扩展Thread类。
由于Java是单一继承,不支持多重继承,所以不能写一个多线程的Applet。
因为如果写多线程的Applet的话,就要扩展Applet和Thread类,而这在Java中是不允许的。
由于这个原因,Java给出了另一个创建线程的方法。
另一种方法是使用接口。
java 多线程理解
Java多线程是指在同一时间内,程序中有多个线程在同时执行。
这种并发性质让程序可以更有效地利用CPU资源,提高程序的响应速度和并发处理能力。
Java多线程的实现方式有两种,一种是继承Thread类,另一种是实现Runnable接口。
对于简单的多线程任务,继承Thread类更为简单,而对于复杂的任务,实现Runnable接口更为灵活。
Java多线程的核心概念包括线程安全、同步和互斥。
线程安全
是指多个线程同时调用一个对象或方法时,不会发生错误或数据损坏。
同步是指多个线程在执行时,需要互相协调和配合,确保数据的正确性和一致性。
互斥是指多个线程在访问共享资源时,需要通过加锁和释放锁来保证同一时间只有一个线程可以访问。
Java多线程的应用领域非常广泛,例如服务器端的并发处理、
多媒体处理、网络编程等等。
理解Java多线程的核心概念和实现方式,对于开发高并发、高可用的程序非常重要。
- 1 -。
一、介绍在Java中,线程的等待是指一个线程暂时停止执行以等待某个条件的触发。
线程的等待通常与锁相关联,当线程等待时,它会释放持有的锁,从而允许其他线程进入临界区。
Java提供了多种方法让线程进入等待状态,本文将为您详细介绍这些方法。
二、w本人t()方法w本人t()方法是Object类中的一个实例方法,它使当前线程进入等待状态,直到其他线程调用notify()或notifyAll()方法唤醒它。
w本人t()方法必须在同步块或同步方法中调用,否则会抛出IllegalMonitorStateException异常。
w本人t()方法也可以指定等待的时间,超过指定时间后线程会自动唤醒。
三、join()方法join()方法是Thread类中的一个实例方法,它使当前线程等待指定线程执行完毕。
当调用join()方法时,当前线程会进入等待状态,直到指定线程执行完毕才会继续执行。
四、sleep()方法sleep()方法是Thread类中的一个静态方法,它使当前线程进入休眠状态,指定的时间过后再重新唤醒。
sleep()方法不会释放锁,因此其他线程无法访问该线程的同步块或同步方法。
五、park()方法park()方法是LockSupport类中的一个静态方法,它使当前线程进入等待状态,直到其他线程调用unpark()方法唤醒它。
与w本人t()方法不同,park()方法不需要在同步块或同步方法中调用。
六、aw本人t()方法aw本人t()方法是Condition接口中的一个实例方法,它使当前线程进入等待状态,直到其他线程调用signal()或signalAll()方法唤醒它。
与w本人t()方法类似,aw本人t()方法必须在Lock对象的控制下调用。
七、总结通过本文的介绍,我们详细了解了Java中让线程进入等待的方法,包括w本人t()、join()、sleep()、park()和aw本人t()等方法。
这些方法各有特点,可以根据实际需求选择合适的方法来实现线程的等待。
第11章 多线程编程 和其他多数计算机语言不同,Java内置支持多线程编程(multithreaded programming。多线程程序包含两条或两条以上并发运行的部分。程序中每个这样的部分都叫一个线程(thread),每个线程都有独立的执行路径。因此,多线程是多任务处理的一种特殊形式。 你一定知道多任务处理,因为它实际上被所有的现代操作系统所支持。然而,多任务处理有两种截然不同的类型:基于进程的和基于线程的。认识两者的不同是十分重要的。对很多读者,基于进程的多任务处理是更熟悉的形式。进程(process)本质上是一个执行的程序。因此,基于进程(process-based) 的多任务处理的特点是允许你的计算机同时运行两个或更多的程序。举例来说,基于进程的多任务处理使你在运用文本编辑器的时候可以同时运行Java编译器。在基于进程的多任务处理中,程序是调度程序所分派的最小代码单位。 在基于线程(thread-based) 的多任务处理环境中,线程是最小的执行单位。这意味着一个程序可以同时执行两个或者多个任务的功能。例如,一个文本编辑器可以在打印的同时格式化文本。所以,多进程程序处理“大图片”,而多线程程序处理细节问题。 多线程程序比多进程程序需要更少的管理费用。进程是重量级的任务,需要分配它们自己独立的地址空间。进程间通信是昂贵和受限的。进程间的转换也是很需要花费的。另一方面,线程是轻量级的选手。它们共享相同的地址空间并且共同分享同一个进程。线程间通信是便宜的,线程间的转换也是低成本的。当Java程序使用多进程任务处理环境时,多进程程序不受Java的控制,而多线程则受Java控制。 多线程帮助你写出CPU最大利用率的高效程序,因为空闲时间保持最低。这对Java运行的交互式的网络互连环境是至关重要的,因为空闲时间是公共的。举个例子来说,网络的数据传输速率远低于计算机处理能力,本地文件系统资源的读写速度远低于CPU的处理能力,当然,用户输入也比计算机慢很多。在传统的单线程环境中,你的程序必须等待每一个这样的任务完成以后才能执行下一步——尽管CPU有很多空闲时间。多线程使你能够获得并充分利用这些空闲时间。 如果你在Windows 98 或Windows 2000这样的操作系统下有编程经验,那么你已经熟悉了多线程。然而,Java管理线程使多线程处理尤其方便,因为很多细节对你来说是易于处理的。
11.1 Java线程模型 Java运行系统在很多方面依赖于线程,所有的类库设计都考虑到多线程。实际上,Java使用线程来使整个环境异步。这有利于通过防止CPU循环的浪费来减少无效部分。 为更好的理解多线程环境的优势可以将它与它的对照物相比较。单线程系统的处理途径是使用一种叫作轮询的事件循环方法。在该模型中,单线程控制在一无限循环中运行, 第1部分 Java语言 192 轮询一个事件序列来决定下一步做什么。一旦轮询装置返回信号表明,已准备好读取网络文件,事件循环调度控制管理到适当的事件处理程序。直到事件处理程序返回,系统中没有其他事件发生。这就浪费了CPU时间。这导致了程序的一部分独占了系统,阻止了其他事件的执行。总的来说,单线程环境,当一个线程因为等待资源时阻塞(block,挂起执行),整个程序停止运行。 Java多线程的优点在于取消了主循环/轮询机制。一个线程可以暂停而不影响程序的其他部分。例如,当一个线程从网络读取数据或等待用户输入时产生的空闲时间可以被利用到其他地方。多线程允许活的循环在每一帧间隙中沉睡一秒而不暂停整个系统。在Java程序中出现线程阻塞,仅有一个线程暂停,其他线程继续运行。 线程存在于好几种状态。线程可以正在运行(running)。只要获得CPU时间它就可以运行。运行的线程可以被挂起(suspend),并临时中断它的执行。一个挂起的线程可以被恢复(resume,允许它从停止的地方继续运行。一个线程可以在等待资源时被阻塞(block)。在任何时候,线程可以终止(terminate),这立即中断了它的运行。一旦终止,线程不能被恢复。
11.1.1 线程优先级 Java给每个线程安排优先级以决定与其他线程比较时该如何对待该线程。线程优先级是详细说明线程间优先关系的整数。作为绝对值,优先级是毫无意义的;当只有一个线程时,优先级高的线程并不比优先权低的线程运行的快。相反,线程的优先级是用来决定何时从一个运行的线程切换到另一个。这叫“上下文转换”(context switch)。决定上下文转换发生的规则很简单:
・ 线程可以自动放弃控制。在I/O未决定的情况下,睡眠或阻塞由明确的让步来完成。在这种假定下,所有其他的线程被检测,准备运行的最高优先级线程被授予CPU。 ・ 线程可以被高优先级的线程抢占。在这种情况下,低优先级线程不主动放弃,处理器只是被先占——无论它正在干什么——处理器被高优先级的线程占据。基本上,一旦高优先级线程要运行,它就执行。这叫做有优先权的多任务处理。
当两个相同优先级的线程竞争CPU周期时,情形有一点复杂。对于Windows98这样的操作系统,等优先级的线程是在循环模式下自动划分时间的。对于其他操作系统,例如Solaris 2.x,等优先级线程相对于它们的对等体自动放弃。如果不这样,其他的线程就不会运行。
警告:不同的操作系统下等优先级线程的上下文转换可能会产生错误。 11.1.2 同步性 因为多线程在你的程序中引入了一个异步行为,所以在你需要的时候必须有加强同步性的方法。举例来说,如果你希望两个线程相互通信并共享一个复杂的数据结构,例如链表序列,你需要某些方法来确保它们没有相互冲突。也就是说,你必须防止一个线程写入数据而另一个线程正在读取链表中的数据。为此目的,Java在进程间同步性的老模式基础 第11章 多线程编程 193 上实行了另一种方法:管程(monitor)。管程是一种由C.A.R.Hoare首先定义的控制机制。你可以把管程想象成一个仅控制一个线程的小盒子。一旦线程进入管程,所有线程必须等待直到该线程退出了管程。用这种方法,管程可以用来防止共享的资源被多个线程操纵。 很多多线程系统把管程作为程序必须明确的引用和操作的对象。Java提供一个清晰的解决方案。没有“Monitor”类;相反,每个对象都拥有自己的隐式管程,当对象的同步方法被调用时管程自动载入。一旦一个线程包含在一个同步方法中,没有其他线程可以调用相同对象的同步方法。这就使你可以编写非常清晰和简洁的多线程代码,因为同步支持是语言内置的。
11.1.3 消息传递 在你把程序分成若干线程后,你就要定义各线程之间的联系。用大多数其他语言规划时,你必须依赖于操作系统来确立线程间通信。这样当然增加花费。然而,Java提供了多线程间谈话清洁的、低成本的途径——通过调用所有对象都有的预先确定的方法。Java的消息传递系统允许一个线程进入一个对象的一个同步方法,然后在那里等待,直到其他线程明确通知它出来。
11.1.4 Thread 类和Runnable 接口 Java的多线程系统建立于Thread类,它的方法,它的共伴接口Runnable基础上。Thread类封装了线程的执行。既然你不能直接引用运行着的线程的状态,你要通过它的代理处理它,于是Thread 实例产生了。为创建一个新的线程,你的程序必须扩展Thread 或实现Runnable接口。 Thread类定义了好几种方法来帮助管理线程。本章用到的方法如表11-1所示:
表11-1 管理线程的方法 方法 意义 getName 获得线程名称 getPriority 获得线程优先级 jsAlive 判定线程是否仍在运行 join 等待一个线程终止 run 线程的入口点. sleep 在一段时间内挂起线程 start 通过调用运行方法来启动线程
到目前为止,本书所应用的例子都是用单线程的。本章剩余部分解释如何用Thread 和Runnable 来创建、管理线程。让我们从所有Java程序都有的线程:主线程开始。
11.2 主 线 程 当Java程序启动时,一个线程立刻运行,该线程通常叫做程序的主线程(main thread), 第1部分 Java语言 194 因为它是程序开始时就执行的。主线程的重要性体现在两方面: ・ 它是产生其他子线程的线程 ・ 通常它必须最后完成执行,因为它执行各种关闭动作。
尽管主线程在程序启动时自动创建,但它可以由一个Thread对象控制。为此,你必须调用方法currentThread()获得它的一个引用,currentThread()是Thread类的公有的静态成员。它的通常形式如下:
static Thread currentThread( ) 该方法返回一个调用它的线程的引用。一旦你获得主线程的引用,你就可以像控制其他线程那样控制主线程。 让我们从复习下面例题开始:
// Controlling the main Thread. class CurrentThreadDemo { public static void main(String args[]) { Thread t = Thread.currentThread();
System.out.println("Current thread: " + t); // change the name of the thread t.setName("My Thread"); System.out.println("After name change: " + t);
try { for(int n = 5; n > 0; n--) { System.out.println(n); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println("Main thread interrupted"); } } }
在本程序中,当前线程(自然是主线程)的引用通过调用currentThread()获得,该引用保存在局部变量t中。然后,程序显示了线程的信息。接着程序调用setName()改变线程的内部名称。线程信息又被显示。然后,一个循环数从5开始递减,每数一次暂停一秒。暂停是由sleep()方法来完成的。Sleep()语句明确规定延迟时间是1毫秒。注意循环外的try/catch块。Thread类的sleep()方法可能引发一个InterruptedException异常。这种情形会在其他线程想要打搅沉睡线程时发生。本例只是打印了它是否被打断的消息。在实际的程序中,你必须灵活处理此类问题。下面是本程序的输出: