线程并发库

创建多线程

1.继承Thread类,重写run方法是覆盖Thread类run方法

2.创建Runnable,重写run方法,是Thread的target

定时器 (java.util.Timer)

schedule:调度

3.线程互斥

线程安全:多个线程同时操作一个共享对象。

对象锁(必须是同一个锁)  类锁

4.线程互斥和通信

将控制台日志输出到文件


要用到共同数据(包括锁)要设计到同一个方法上,是高内聚低耦合的一个体现。以下是例子

题目:子线程循环10次,接着主线程执行100次,接着又回到子线程执行10次,接着再回到主线程执行100次,如此循环50次,请写出程序。

public class TraditionalThreadCommunication {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		final Business business = new Business();
		new Thread(
				new Runnable() {
					
					@Override
					public void run() {
					
						for(int i=1;i<=50;i++){
							business.sub(i);
						}
						
					}
				}
		).start();
		
		for(int i=1;i<=50;i++){
			business.main(i);
		}
		
	}

}
  class Business {
	  private boolean bShouldSub = true;
	  public synchronized void sub(int i){
		  while(!bShouldSub){
			  try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		  }
			for(int j=1;j<=10;j++){
				System.out.println("sub thread sequence of " + j + ",loop of " + i);
			}
		  bShouldSub = false;
		  this.notify();
	  }
	  
	  public synchronized void main(int i){
		  	while(bShouldSub){
		  		try {
					this.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		  	}
			for(int j=1;j<=100;j++){
				System.out.println("main thread sequence of " + j + ",loop of " + i);
			}
			bShouldSub = true;
			this.notify();
	  }
  }
5.线程范围内的数据是独立的,线程内共享数据,线程外独立数据。---典型ThreadLocal

6.ThreadLocal等同Map,放数据threadLocal.set(data);

                                         取数据threadLocal.get();

一个ThreadLocal代表一个变量,故其中只能放一个数据。你有两个变量都要线程范围内共享,则要定义两个ThreadLocal对象。如果有一百个变量要共享,那么先定义一个对象装这一百个变量,然后在ThreadLocal中存储这一对象。

单例模式中将实例添加到ThreadLocal,代码实现更优雅。

class MyThreadScopeData{
	private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
	private MyThreadScopeData(){}
	public static MyThreadScopeData getThreadInstance(){
		MyThreadScopeData instance = map.get();
		if(instance == null){
			instance = new MyThreadScopeData();
			map.set(instance);
		}
		return instance;
	}
虚拟机对应Runntime类

addShutdowhook():注册回调思想。

可以捕获线程死亡前事件:回调,清理ThreadLocal中对象

8.多个线程访问共享数据方式,可以封装Runnable对象。

题目:设计4个线程,其中2个每次对j加1,另外2个线程对j每次j减1,写出程序。

public class ThreadTest2 {
	private int j;
	public static void main(String[] args) throws Exception {
		ThreadTest2 tt = new ThreadTest2();
		Inc inc = tt.new Inc();
		Dec dec = tt.new Dec();
		for(int i=0;i<2;i++) {
			Thread t = new Thread(inc);
			t.start();
			t.join();
			t = new Thread(dec);
			t.start();
			t.join();
		}
	}
	private synchronized void inc() {
		j++;
		System.out.println(Thread.currentThread().getName()+"-inc:"+j);
	}
	private synchronized void dec() {
		j--;
		System.out.println(Thread.currentThread().getName()+"-dec:"+j);
	}
	
	class Inc implements Runnable{
		@Override
		public void run() {
			for(int i=0;i<100;i++) {
				inc();
			}
		}
	}
	class Dec implements Runnable{
		@Override
		public void run() {
			for(int i=0;i<100;i++) {
				dec();
			}
		}
	}
}

10.线程池框架


Executors

创建固定大小的线程池

创建缓存线程池

创建单一线程池(线程死后会重新启动一个新的线程)

关闭线程池

shutdown和shutdownNow的区别

shutdown会等待线程执行完后关闭线程池

shutdownNow不等待直接关闭

用线程池启动定时器

10.Callable和Future:获得线程返回或执行结果

Callable要采用ExecutorService的submit方法提交,返回的Future对象可以取消任务。

Future取得的结果类型和Callable返回的结果类型必须一致,这是通过泛型来实现的。

ExecutorService.execute(Runnable)    void

ExecutorService.submit(Callable)   Future

CompletionService用于提交一组Callable任务,其take方法返回已经完成的一个Callable任务对应的Future对象。

11.Lock&Condtion:实现线程互斥和通信

Lock比Synorchized更面向对象,两个线程执行的代码片段要是实现同步互斥的效果,它们必须用同一个Lock对象。锁是上在代表要操作的资源的类的内部方法中,而不是线程代码中。

Condtion功能类似传统工程中Object.wait()和Object.notify()功能。在等待Condtion时,允许发生虚假唤醒,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为Condtion应该总是在一个循环中被等待,并测试正被等待的状态生命。某个实现可以随意的移除虚假唤醒,但建议应用程序总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。

一个锁内部可以有多个Condtion,既有多路等待和通知。object的wait、notify只能一路等待。

static class Outputer{
		Lock lock = new ReentrantLock();
		public void output(String name){
			int len = name.length();
			lock.lock();
			try{
				for(int i=0;i<len;i++){
					System.out.print(name.charAt(i));
				}
				System.out.println();
			}finally{
				lock.unlock();
			}
		}
读写锁:分为读锁和写锁。多个读锁不互斥,读锁与写锁互斥。写锁与写锁互斥。

class Queue3{
	private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
	ReadWriteLock rwl = new ReentrantReadWriteLock();
	public void get(){
		rwl.readLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + " be ready to read data!");
			Thread.sleep((long)(Math.random()*1000));
			System.out.println(Thread.currentThread().getName() + "have read data :" + data);			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			rwl.readLock().unlock();
		}
	}
	
	public void put(Object data){

		rwl.writeLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + " be ready to write data!");					
			Thread.sleep((long)(Math.random()*1000));
			this.data = data;		
			System.out.println(Thread.currentThread().getName() + " have write data: " + data);					
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			rwl.writeLock().unlock();
		}
		
	
	}
}
锁降级:在释放写锁前,挂一把读锁。
设计一个缓存系统

public class CacheDemo {

	private Map<String, Object> cache = new HashMap<String, Object>();
	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 = "aaaa";//实际查询库queryDB();
					}
				}finally{
					rwl.writeLock().unlock();
				}
				rwl.readLock().lock();
			}
		}finally{
			rwl.readLock().unlock();
		}
		return value;
	}
}
Condtion的使用

static class Business {
		  Lock lock = new ReentrantLock();
		  Condition condition = lock.newCondition();
		  private boolean bShouldSub = true;
		  public  void sub(int i){
			  lock.lock();
			  try{
				  while(!bShouldSub){
					  try {
						condition.await();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				  }
					for(int j=1;j<=10;j++){
						System.out.println("sub thread sequence of " + j + ",loop of " + i);
					}
				  bShouldSub = false;
				  condition.signal();
			  }finally{
				  lock.unlock();
			  }
		  }
		  
		  public  void main(int i){
			  lock.lock();
			  try{
				 while(bShouldSub){
				  		try {
							condition.await();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
				  	}
					for(int j=1;j<=100;j++){
						System.out.println("main thread sequence of " + j + ",loop of " + i);
					}
					bShouldSub = true;
					condition.signal();
		  }finally{
			  lock.unlock();
		  }
	  }
	
	}

多路Condtion情况实现可阻塞缓冲队列

class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length) 
         notFull.await();
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) 
         notEmpty.await();
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }
14.java5 Semaphore实现信号灯,Semaphore可以维护当前访问自身的线程的个数,并提供了同步机制。使用Semaphore可以同时访问资源的线程个数,例如:实现一个文件允许的并发访问数。

单个信号量的Semaphore对象可以实现互斥锁功能,并且可以是由一个线程获得了锁,再由另一个线程释放锁,这可以用于死锁回复的一些场合。

15.其他同步工具类
CyclicBarrier:表示大家彼此等待,大家集合好后才出发,分散活动后又在指定的地点集合。比如:旅游
CountDownLatch:犹如倒计时计数器,调用CountDownLatch的countDown()方法就将计数器减1,当计数到达0时,则所有等待者或单个等待着开始执行。

可以向CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。
例如:百米赛跑。裁判吹哨,3个运动员跑。在终点裁判等待结果,总共是3,来一个计数器减1,都到后计数器减为0,裁判开始公布成绩。
可以实现一个人等多个人,或多个人等一个人
Exchanger:用于实现两个人之间的数据交换,每个人在完成一定的事务后想与对方交换数据,第一个先拿出数据的人将一直等待第二人拿着数据到来,才能彼此交换数据。
例如:卖东西的用东西交换钱,买东西的用钱交换东西。卖东西先到等待,买东西先到也等待。两者同时到达后开始交换数据。
18.并发库下集合
阻塞队列:顶级接口BlockingQueue
SynchronousQueue:同步队列,每个插入操作必须等待另一个线程的对应移除操作
队列包含固定长度的队列和不固定长度的队列。
阻塞队列:ArrayBlockingQueue
阻塞队列和Semaphore有些类似,但也不同。阻塞队列是一方存数据,另一方释放数据。Semaphore通常则是由同一方设置和释放信号量。

匿名构造方法:没有名字的构造方法,每创建一个对象就执行一次。

{
			  Collections.synchronizedMap(null);

			  try {
				System.out.println("xxxxxdfsdsafdsa");
				queue2.put(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		  }

static构造方法:类加载时执行一次,且只执行一次。

死锁:两个线程去拿同一把锁,线程1先拿到,却因某种原因阻塞在那里,线程2在等待拿锁。程序看上去卡死在里。

数组与链表区别:数组是连续的内存空间,链表不连续

并发集合

hashmap

hashset:hashset的内部使用的是hashmap。是hashmap的key。

java5前集合问题:1.线程不安全   2.迭代集合(ArrayList)时添加、删除都有问题

copyOnWriteArrayList:写时拷贝,解决了集合迭代时添加和删除的问题。

wait和sleep区别

wait会释放锁

sleep不会释放















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值