1、什么是并发
已知:多个进程或线程同时(或者说在同一段时间内)访问同一资源会产生并发问题。
1.1并发程序:
并发程序设计(concurrent programming)是指由若干个可在同一时间段执行的程序模块组成程序的程序设计方法。这种可并发执行的程序模块称为进程。进程由数据和机器指令和堆栈组成。组成一个程序的多个进程可以同时在多台处理器上并行执行,也可以在一台处理器上夹插执行。采用并发程序设计可以使外围设备和处理器并行工作,缩短程序执行时间,提高计算机系统的效率。在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
1.2并发访问:
在关系数据库中,允许多个用户同时访问和更改共享数据的进程。SQL Server 使用锁定以允许多个用户同时访问和更改共享数据而彼此之间不发生冲突。
1.3并发与并行的区别
并发和并行是即相似又有区别的两个概念,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。在多道程序环境下,并发性是指在一段时间内宏观上有多个程序在同时运行,但在单处理机系统中,每一时刻却仅能有一道程序执行,故微观上这些程序只能是分时地交替执行。倘若在计算机系统中有多个处理机,则这些可以并发执行的程序便可被分配到多个处理机上,实现并行执行,即利用每个处理机来处理一个可并发执行的程序,这样,多个程序便可以同时执行。
1.4程序并发的特点
(1)程序与计算不再一一对应,一个程序副本可以有多个计算
(2)并发程序之间有相互制约关系,直接制约体现为一个程序需要另一个程序的计算结果,间接制约体现为多个程序竞争某一资源,如处理机、缓冲区等。
(3)并发程序在执行中是走走停停,断续推进的。
1.5现实中的并发例子
银行两操作员同时操作同一账户就是典型的例子。比如A、B操作员同时读取一余额为1000元的账户,A操作员为该账户增加100元,B操作员同时为该账户减去 50元,A先提交,B后提交。 最后实际账户余额为1000-50=950元,但本该为 1000+100-50=1050。
2、如何处理并发
(1)程序在操作数据库的时候使用事务处理
(2)使用Hibernate的锁机制 悲观锁
(3)程序中使用同步异步、锁、多线程开启线程处理
3、JDK处理并发机制
在JDK1.5之前程序员需要手动编写多线程程序处理并发,JDK1.5之后Sun就提供了concurrent的处理包来处理并发问题了。总的来说就是使用线程池、锁、队列等的处理机制来处理并发。
以下是几个concurrent的核心类:
Executor :具体Runnable任务的执行者。
ExecutorService :一个线程池管理者,其实现类有多种,能把Runnable,Callable提交到池中让其调度。
Semaphore :一个计数信号量
ReentrantLock :一个可重入的互斥锁定 Lock,功能类似synchronized,但要强大的多。
Future :是与Runnable,Callable进行交互的接口,比如一个线程执行结束后取返回的结果等等,还提供了cancel终止线程。
BlockingQueue :阻塞队列。
CompletionService : ExecutorService的扩展,可以获得线程执行结果的
CountDownLatch :一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
CyclicBarrier :一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点
Future :Future 表示异步计算的结果。
ScheduledExecutorService :一个 ExecutorService,可安排在给定的延迟后运行或定期执行的命令。
........................
4、并发线程池使用示例
package com.boonya.concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 多线程线程池使用示例
* @author [email protected]
* 查看线程执行的过程,以及并发处理的流程
*/
public class ConcurrentThreadPool {
/**
* 执行方法doSomething
* @param id
*/
private static void doSomething(int id) {
System.out.println("start do " + id + " task …");
try {
Thread.sleep(1000 * 2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("start do " + id + " finished.");
}
/**
* 开启线程并发测试
* @param args
*/
public static void main(String[] args) {
//创建了一个线程池,里面有2个线程
ExecutorService executorService = Executors.newFixedThreadPool(2);
//通过submit()方法,提交一个Runnable的实例,这个实例将交由线程池中空闲的线程执行
executorService.submit(new Runnable() {
@Override
public void run() {
doSomething(1);
}
});
executorService.submit(new Runnable() {
@Override
public void run() {
doSomething(2);
}
});
executorService.submit(new Runnable() {
@Override
public void run() {
doSomething(3);
}
});
//结束主线程,因为main函数也是一个线程
//不必担心,线程池不会直接关闭的,只有当它执行完所有提交的任务后才会关闭。
//如果不写这行,在本例中,应用将不会停止,因为虽然main线程(就是运行main
//方法的线程,也叫主线程)退出了,但是线程池中依然有线程运行,因此应用(进程)不会退出。
executorService.shutdown();
System.out.println(">>main thread end.");
}
}