----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
孝祥老师Java5线程并发库讲解---截图标记笔记
java.util.concurrent.atomic
类 AtomicIntegerFieldUpdater
基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。
线程并发库的应用
由tomcat原理引出线程池:
我们做一个tomcat服务器很难,难在于我们的性能提升不上去
Java5.0中提供的线程池[ThreadPool]
Shutdown:启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
shutdownNow:试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
package cn.itcast.extend.thread;
//java5线程并发库的应用-----线程池
//线程池中就两个东西:1,线程池中有几个线程 2,往里丢了几个任务 [将任务丢进去就ok了,不用去管,只要有空余线程就自动去接待任务]
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class ThreadPoolTest {
public static void main(String[] args) {
//固定的线程池,自定义线程数量 ExecutorService threadPool=Executors.newFixedThreadPool(3);
//动态的线程池,给几个任务,就自动创建几个线程 ExecutorService threadPool=Executors.newCachedThreadPool();
ExecutorService threadPool=Executors.newSingleThreadExecutor();//建立一个单一线程池:好处,永远保证池子中有一个线程
//可以实现线程死掉后又复活的现象.
for(int i=1;i<=10;i++){
final int task=i;
threadPool.execute(new Runnable() {//往线程池中丢任务
@Override
public void run() {
for(int i=1;i<=10;i++){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" is looping of "+i+" for task of "+task);
}
}
});
//threadPool.shutdownNow();立即将线程池中的所有线程干掉.
//会报异常----java.lang.InterruptedException: sleep interrupted
}
System.out.println("all of 10 tasks hava committed!");
//threadPool.shutdown();//所有的任务都干完了.线程们都空闲了,就关掉池子,销毁池子中的所有线程
//用线程池启动定时器------缺陷不能指定绝对的时间
//解决缺陷的方法:date.getTime()-System.currentTimeMillis();
ScheduledFuture s=Executors.newScheduledThreadPool(3).scheduleAtFixedRate(
new Runnable() {//任务
@Override
public void run() {
System.out.println("bombing!");
}
},
3,//几秒后开炸
2,//频率
TimeUnit.SECONDS//单位
);
//返回的ScheduledFuture对象中有个cancel方法,可以取消当前任务.
//s.cancel(true);
}
}
Callable与Future的应用
读写锁技术的妙用
package cn.itcast.extend.thread;
//java5的线程锁技术
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
public static void main(String[] args) {
LockTest TTS = new LockTest();
TTS.init();
}
// 注意:静态方法中不能new内部类的对象,因为,内部类有一个特性,就是可以访问其外部类的成员变量.所以内部类
// 中存在一个外部类的对象super,而静态方法中根本不存在对象.
public void init() {
final Outputer op = new Outputer();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output("zhangxiaoxiang");
}
}
}).start();
Thread thread1 = new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output("lihuoming");
}
}
};
thread1.start();
}
static class Outputer {
Lock lock = new ReentrantLock();
public void output(String name) {
lock.lock();// 加上锁
try {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
} finally {
lock.unlock();
}
}
}
}
package cn.itcast.extend.thread;
//12_传智播客_张孝祥_java5读写锁技术的妙用[给力--文档上的案例很重要]
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
//----面试题:做一个缓存系统
public class CacheDemo {
private Map cache=new HashMap();
public static void main(String[] args) {
}
//缓存系统:检查内部是否有数据,如果有就直接给他,如果没有,就去数据库中找,找到后给他,并且,缓存起来备用.
//运用读写锁---创建一个读写锁[多个并发的读,性能会提高]
//多个数据来读的时候是并发的,不会造成对数据的破坏,所以,一开始加上读锁.
//加入一个线程发现,内部没有数据,就将读锁关掉,挂上写锁.待写完数据后释放写锁,在激活读锁,实现并发读数据
private ReadWriteLock rwl=new ReentrantReadWriteLock();
public Object getData(String key){
rwl.readLock().lock(); //读锁打开
Object value=null;
try{
value=cache.get(key);
if(value==null){
rwl.readLock().unlock();//如果发现,该数据为空,就将读锁释放.
rwl.writeLock().lock();//打开写锁.---避免在他写的时候,来添乱.
try{
if(value==null)
value="实际是去queryDB()";
}finally{
rwl.writeLock().unlock();//写完后,就将写锁,释放.
}
rwl.readLock().lock();//里面有数据了,为了下面finally中读锁.我再加上读锁.
}
}finally{
rwl.readLock().unlock();
}
return value;
}
}
上面代码,是所属于Hibernate的.下面有相关介绍:
Hibernate
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。
面试题:设计一个缓存系统,中设计到.Api中的一个例子:
条件阻塞Condition的应用
package cn.itcast.extend.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//java5条件阻塞Condition的应用
//一道面试题:子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,如此循环50次.交替进行.
public class ConditionCommunication {
public static void main(String[] args) {
final Business business=new ConditionCommunication().new Business();
System.out.println("Hello");
//new一个线程(子线程)
new Thread(
new Runnable(){
@Override
public void run() {
for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();
//main主线程
for(int i=1;i<=50;i++){
business.main(i);
}
}
/*经验:要用到共同数据(包括同步锁)或共同算法的若干个方法应该归在同一个类身上,这种设计正好体现了高类聚
和程序的健壮性*/
class Business{
Lock lock=new ReentrantLock();
Condition conditionSub=lock.newCondition();
Condition conditionMain=lock.newCondition();
private int flag=2;
//一定要注意,用lock了,就别用Synchronized,这样会死锁的...................................
//子线程
public void sub(int i){//如果去掉synchronized,就会报错.
lock.lock();
try{
while(flag!=2){
conditionSub.await();
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of:"+j+",loop of:"+i);
}
flag=1;
conditionMain.signal();
}catch(Exception e){
e.printStackTrace();
}
finally{
lock.unlock();
}
}
//主线程
public void main(int i){
lock.lock();
try{
while(flag!=1){
conditionMain.await();
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of:"+j+",loop of:"+i);
}
flag=2;
conditionSub.signal();
}catch(Exception e){
System.out.println(e);
}
finally{
lock.unlock();
}
}
}
}
其中,涉及到-----阻塞的队列底层实现
Api提供的实例:
Semaphere同步工具
Lock锁,和Semaphore实现互斥锁的区别:
Lock只能被,加锁的对象锁释放.而Semaphore被锁上后,还可以被别人释放.
下面,是在构造函数中,修改fair,为true来改变先来后到的顺序....
package cn.itcast.extend.thread;
/*semaphore
|---acquire();获取
|---release();释放
|--availablePermits;有效的许可
*/
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
ExecutorService service=Executors.newCachedThreadPool();
final Semaphore sp=new Semaphore(3);
for(int i=0;i<10;i++){
Runnable runnable=new Runnable() {
@Override
public void run() {
try{
sp.acquire();//acquire[获取]
}catch(InterruptedException e1){
e1.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"进入,当前已有"+
(3-sp.availablePermits())+"个并发");
try{
Thread.sleep((long)(Math.random()*10000));
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"即将离开");
sp.release();//release[释放]
System.out.println("线程"+Thread.currentThread().getName()+"已离开,当前已有"
+(3-sp.availablePermits())+"个并发");
}
};
service.execute(runnable);
}
}
}
CyclicBarrier同步工具
package cn.itcast.extend.thread;
//java5的CyclicBarrier同步工具
/*CyclicBarrier
|-----await();
|-----getNumberWaiting();返回当前在屏障处等待的参与者数目。此方法主要用于调试和断言。
*/
//
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest {
public static void main(String[] args) {
//来一个动态的线程池
ExecutorService service = Executors.newCachedThreadPool();
//建一个障碍.....主角上场...
final CyclicBarrier cb=new CyclicBarrier(3);
//循环三次,往线程池中丢三次....
for (int i = 1; i <= 3; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
//随机生成时间,来代表每个小伙伴们到达的时间
Thread.sleep((long) (Math.random() * 10000));//千万记着括号......罪过..
System.out.println("线程"
+ Thread.currentThread().getName()
+ "即将到达集合地点1,当前已有"
+ (cb.getNumberWaiting()+1)// 返回当前在屏障处等待的参与者数目。
+ "个已经到达,"
+ (cb.getNumberWaiting() == 2 ? "都到齐了,继续走啊"
: "正在等候"));
cb.await();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程"
+ Thread.currentThread().getName()
+ "即将到达集合地点2,当前已有"
+ (cb.getNumberWaiting() + 1)//这里加1,是因为,这个线程还没走到下面那个await().
+ "个已经到达," //此时,返回是0,所以,这里是预先打印出来的.
+ (cb.getNumberWaiting() == 2 ? "都到齐了,继续走啊"//这里判断==2,是这个情况.
: "正在等候"));
cb.await();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程"
+ Thread.currentThread().getName()
+ "即将到达集合地点3,当前已有"
+ (cb.getNumberWaiting() + 1)
+ "个已经到达"
+ (cb.getNumberWaiting() == 2 ? ",都到齐了,不用走了,休息下吃点饭把."
: "正在等候"));
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);//每建一个Runnble后,将其丢尽线程池中...
}
service.shutdown();//最后,所有的线程都闲了,,就关掉池子把...
}
}
package cn.itcast.extend.thread;
//java5的CountDownLatch同步工具 CountDown[倒计时] Latch[锁存器]
//可以模拟:运动场上,裁判一声"枪"下,运动员们听到枪声后,开始跑百米,当这几个运动员全部,跑完后,裁判员再公布名次.
/*CountDownLatch
|------await(); 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
|------countDown(); 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
*/
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchTest {
public static void main(String[] args){
//老样子,来一个,线程池
ExecutorService service=Executors.newCachedThreadPool();
//两个(计数器)
final CountDownLatch cdOrder=new CountDownLatch(1);//Order[命令]
final CountDownLatch cdAnswer=new CountDownLatch(3);//Answer[回答,回应]
//循环三次.创造线程.
for(int i=1;i<=3;i++){
Runnable runnable=new Runnable() {
@Override
public void run() {
try {
System.out.println("线程"+Thread.currentThread().getName()+"正准备接受命令");
cdOrder.await();//当计数器中,的数字变成1的时候,就可以,继续往下走.
System.out.println("线程"+Thread.currentThread().getName()+"已经接受命令");
Thread.sleep((long)(Math.random()*10000));//这个任务需要一定的时间哈...[比如跑百米]
System.out.println("线程"+Thread.currentThread().getName()+"回应命令处理结果");
cdAnswer.countDown();// 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);//丢尽线程池
}
try{
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程"+Thread.currentThread().getName()+"即将发布命令");
cdOrder.countDown();
System.out.println("线程"+Thread.currentThread().getName()+"已发送命令,正在等待结果");
cdAnswer.await();
System.out.println("线程"+Thread.currentThread().getName()+"已收到所有响应结果");
}catch(Exception e){
e.printStackTrace();
}
service.shutdown();
}
}
package cn.itcast.extend.thread;
//java5的Exchanger同步工具
//可以模拟,双方共到一个目的地交换彼此的物件.
//两个线程碰到一起后,互相交换数据
/*Exchanger
|-----exchange(V x)等待另一个线程到达此交换点(除非当前线程被中断),然后将给定的对象传送给该线程,并接收该线程的对象。
*/
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExchangerTest {
public static void main(String[] args) {
ExecutorService servise=Executors.newCachedThreadPool();//一个动态的线程池
final Exchanger exchanger=new Exchanger();
//往线程池中丢一个线程.
servise.execute(new Runnable() {
@Override
public void run() {
try{
String data="物";
System.out.println("线程"+Thread.currentThread().getName()+"到达目的地");
System.out.println("线程"+Thread.currentThread().getName()+"正在把数据["+data+"]换出去");
Thread.sleep((long)(Math.random()*10000));
data=exchanger.exchange(data);
System.out.println("线程"+Thread.currentThread().getName()+"换回的数据为["+data+"]");
}catch(Exception e){
e.printStackTrace();
}
}
});
//往线程池中再丢一个线程.
servise.execute(new Runnable() {
@Override
public void run() {
try{
String data="钱";
System.out.println("线程"+Thread.currentThread().getName()+"到达目的地");
System.out.println("线程"+Thread.currentThread().getName()+"正在把数据["+data+"]换出去");
Thread.sleep((long)(Math.random()*10000));
data=exchanger.exchange(data);
System.out.println("线程"+Thread.currentThread().getName()+"换回的数据为["+data+"]");
}catch(Exception e){
e.printStackTrace();
}
}
});
servise.shutdown();
}
}
java5阻塞队列的应用
同步集合类的应用
讲之前,先看看并发库中已经学过的知识们:
都在java.util.concurrent包中---------
其中老师谈到,在队列中,有两个实现类,1,linked链表[可以不固定大小] 2,Array[必须固定大小]
底层机制:连续的一片内存[数组] 不连续的一片内存[链表]
在没有1.5并发库之前,实现多线程访问集合,可以用Collections中的SynchronizedMap();
在迭代器中不能对集合中的数据进行操作----------原理.