所谓并发编程是指在一台处理器上"同时"处理多个任务。并发是在同一实体上的多个事件。多个事件在同一时间间隔发生。
一、程序与进程
程序是一组有序指令的集合,是一种静态的概念。进程是程序的一次执行,属于一种动态的概念。在多道程序环境下,程序的执行属于并发执行,此时它们将失去封闭性,并具有间断性,运行结果也将不可再现,为了能使多个程序可以并发执行,提高资源利用率和系统吞吐量,并且可以对并发执行的程序加以描述和控制,引入进程的概念。
1丶进程和线程
我们知道,为了能使程序能够并发执行,系统必须进行创建进程、撤销进程以及进程切换等操作,而进程作为一个资源的拥有者,在进行这些操作时必须为之付出较大的时空开销。
线程和进程的区别主要如下:(1) 进程是系统中拥有资源的一个基本单位,线程本身并不拥有系统资源,同一进程内的线程共享进程拥有的资源。(2) 进程仅是资源分配的基本单位,线程是调度和分派的基本单位。(3) 线程的并发性更高,可以启动多个线程执行同程序的不同部分。
2丶并行和并发
并行是指两个或多个线程在 同一时刻 执行,并发是指两个或多个线程在 同一时间间隔 内发生。如果程序同时开启的线程数小于CPU的核数,那么不同进程的线程就可以分配给不同的CPU来运行,这就是并行,如果线程数多于CPU的核数,那就需要并发技术。
二、Java多线程
开启的新线程都有一个线程优先级,代表该线程的重要程度,可以通过Thread类的getPriority()和setPriority()来得到或者设置线程的优先级。线程的优先级范围是1~10,默认情况下是5。
在线程创建完成还未启动的时候,我们可以通过方法setDaemon()来将线程设置为守护线程。守护线程,简单理解为后台运行线程,比如当程序运行时播放背景音乐。守护线程与普通线程在写法上基本没有区别,需要注意的是,当进程中所有非守护线程已经结束或者退出的时候,即使还有守护线程在运行,进程仍然将结束。
终止线程?
1、线程自己在run()方法执行完后自动终止
2、调用Thread.stop()方法强迫停止一个线程,不过此方法是不安全的,已经不再建议使用。
3、比较安全可靠的是利用Java的中断机制,使用方法Thread.interrupt()。需要注意的是,通过中断并不能直接终止另一个线程,需要被中断的线程自己处理中断。被终止的线程一定要添加代码对isInterrupted状态进行处理,否则即使代码是死循环的情况下,线程也将永远不会结束。
三、线程安全
线程安全性不是一个非真即假的命题。 Vector 的方法都是同步的,并且 Vector 明确地设计为在多线程环境中工作。但是它的线程安全性是有限制的,即在某些方法之间有状态依赖(类似地,如果在迭代过程中 Vector 被其他线程修改,那么由 Vector.iterator() 返回的 iterator会抛出ConcurrentModifiicationException)。
这类的规格说明所规定的约束在对象被多个线程访问时仍然有效,不管运行时环境如何排线程都不需要任何额外的同步。这种线程安全性保证是很严格的 -- 许多类,如 Hashtable 或者 Vector 都不能满足这种严格的定义。
四、线程池
在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,JVM将试图跟踪每个对象,以便能够在对象销毁后进行垃圾回收。Java线程池实现了一个Java高并发的、多线程的、可管理的统一调度器,减少创建和销毁线程对象的次数。
下面详细介绍一下Java里的线程池技术,首先看一个类Executors,它是线程的工厂类,方便快速地创建很多线程池。配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚地情况下,很有可能配置的线程池不是最优的,因此在Executors类里提供了一些静态工厂,生成一些常用的线程池,常用的方法有:
-
newSingleThreadExecutor()
创建一个单线程的线程池,这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
-
newFixedThreadExecutor()
传入参数nThreads,创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,最多nThreads个线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务。在某个线程被显示地关闭之前,池中的线程将一直存在。
我们查看newFixedThreadExecutor()的实现,可以看到它里面就是实例化了一个ThreadPoolExecutor,ThreadPoolExecutor的构造函数如下:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
从上面代码可以看到几个参数,corePoolSize表示线程池中线程的稳定峰值,maximumPoolSize表示最大处理线程数,workQueue表示线程等待池,另外在线程池中执行的线程列表是存放在workers中的,它的类型是HashSet<Worker>的。
为了让学习变得轻松、高效,今天给大家免费分享一套Java入门教学资源。帮助大家在成为Java架构师的道路上披荆斩棘。需要资料的欢迎加入学习交流群:9285,05736