java并发编程笔记

-------------------任务执行-------------------
1.CountDownLatch(闭锁) countDown():计数器,当一个线程调用就减1  await() 只有countDown计算机为零以后,await调用的进程才能继续执行。
	完成指定数量的线程以后,被await的线程才能继续执行
	(好比旧社会家里没有吃的,小孩吃完粗粮以后,父母才把剩下的吃了)
	小孩就是指定的多少个线程,父母就是被await方法调用的对象
	//例子CountDownLatch指定的是10个线程
	//contdl.await();只有指定的10个线程都执行完成以后,执行这个方法的线程才能继续
	
	public static void testCountDownLatch(final CountDownLatch contdl){
		for(int i=0;i<10;i++){
			System.out.println("start"+i);
			Thread t=new Thread(new Runnable(){
				@Override
				public void run() {
					try{
						System.out.println("thread start!");
					}catch(Exception e){
						
					}
					finally{
						contdl.countDown();
					}
				}
			});
			
			t.start();
			
			System.out.println("end"+i);
		}
	}
2.FutureTask 例子:
public static void testFutureTask() throws InterruptedException, ExecutionException{
FutureTask<String> fuTask=new FutureTask<String>(new Callable<String>(){
			@Override
			public String call() throws Exception {
				System.out.println("call run");
				return "true";
			}});
		
		Thread thread=new Thread(fuTask);
		thread.start();
		
		String flag=fuTask.get();
		System.out.println(flag);
	}
	执行完成后,会输出ture的字符串,如果在调用get方法之前还没完成线程的执行,可能会中断
	
4.semaphore信号量 用来控制并发过程中,可以执行的进程数量。(同一时间内只能有固定数量的可以执行,好比厕所的坑数量一样)

//Semaphore  semaphore=new Semaphore(2);

public static void testSemaphore(final Semaphore semaphore){
		for(int i=0;i<10;i++){
			Thread t=new Thread(new Runnable(){
				@Override
				public void run() {
					
					try{
						semaphore.acquire();
						System.out.println("thread start!");
						Thread.currentThread().sleep(5000);
					}catch(Exception e){
						
					}
					finally{
						semaphore.release();
					}
				}
			});
			
			t.start();
		}
	}
同时定义了10个线程,但是能同时执行的只有2个。因为在传入的参数进指定了,只能有2个执行	

5.CyclicBarrier栅栏	 用来阻塞一些方法,只有满足CyclicBarrier的条件,才可以放行
CyclicBarrier cyclicBarrier=new CyclicBarrier(10,new Runnable(){
			@Override
			public void run() {
				System.out.println("runnable");
			}
		});
		Test.testCyclicBarrier(cyclicBarrier);


public static void testCyclicBarrier(final CyclicBarrier cyclicbarrier){
		for(int i=0;i<10;i++){
			Thread t=new Thread(new Runnable(){
				@Override
				public void run() {
					
					try{
						System.out.println("thread start1!");
						Thread.currentThread().sleep(2000);
						cyclicbarrier.await();
						System.out.println("thread start2!");
						
					}catch(Exception e){
						e.printStackTrace();
					}
				}
			});
			
			t.start();
		}	
	}
代码会输出thread start1!以后进入阻塞,只有当满足10个的时候,才会执行CyclicBarrier中的runnable线程,完了以后才会执行thread start2!
6.在正常使用中我们多用list(arrayList)和map(hashMap),在并发中为了保证线程安全用ConcurrentHashMap和CopyOnWriteList
7.Executor接口,实现Executor接口的接口ExecutorService和Executor的区别就是添加了生命周期的方法
8.线程池的使用
Executors.newFixedThreadPool(num);创建一个固定大小的线程池
Executors.SimpleThreadPool();单线程
Executors.newScheduledThreadPool();支持定时任务的线程池
Executors.newCachedThreadPool();缓存线程池,可以创建任意个线程池,用完自动回收
example:
	public static void testExecutor() throws InterruptedException, ExecutionException{
		
		ExecutorService executor=Executors.newSingleThreadExecutor();
		Callable<String> task=new Callable<String>(){

			@Override
			public String call() throws Exception {
				System.out.println(Thread.currentThread().getName());
				System.out.println("running!");
				return "ok";
			}};
		Future<String> future=executor.submit(task);
		System.out.println(future.get());
		executor.shutdown();
		System.out.println(executor.isShutdown());
	}
//out
pool-1-thread-1
running!
ok
true

//现实的获取代码段
try {
			System.out.println(future.get(1,TimeUnit.SECONDS));//指定多少秒内获取到数据,如果在指定的时间内没有获取到数据会TimeoutException
		} catch (TimeoutException e) {
			//e.printStackTrace();
			future.cancel(true);//如果抛出TimeoutException异常,就取消该任务。
		}

编写多线程高性能的代码是如果任务执行的时间较长,可以考虑使用限时的等待方法,在指定的时间内如果没有执行完成,就直接取消。
合理的执行线程池的大小对于性能的提高也很有影响

包和策略:(当队列被填满以后,包和策略就可以派上用场了)
AbortPolicy:默认使用该测试,如果队列满了,会抛出RegectdExecutionExecption,我们可以捕获异常做一些处理
CallerRybsPolicy:调用者运行,当使用该策略以后,会将调用线程的执行回退给调用者(可能是主线程)去执行,只要主线程就不会很快速的提交到队列
,如果大并发厉害的话,这样也可能导致tcp队列和客户端整体性能下降(因为提交的越来越多),不过这样可以给线程池足够的时间去消费队列中的任务。
DiscardPloicy:抛弃任务,增加任务
DiscardOldestPolicy:会将队列中下一个任务抛弃掉,尝试将新任务提交到队列中去,如果是一个优先级高的队列会有问题的~


9.毒丸对象(一个标志)
	用来控制线程(队列)的结束	
	例如在生产者消费者队列中,如果要停止该执行线程,只需要产生一个毒丸对象,放到到队列中,当消费者检测到存在毒丸对象的时候退出执行。
	
		
10.如果递归循环没有数据联系,在必要的情况下也可以通过并行来提交执行性能。
11.Lock和ReentrantLock,ReadWriteLock-ReenrantReadWriteLock(Lock的实现类)必要的时候可以使用lock.tryLock();用来获取锁
12.如果线程在休眠或者阻塞时持有一个锁,通常是一种不好的做法,影响其他线程对资源的访问,可能造成更大的性能下降
13.线程的6种状态:new runnable blocked waiting timewaiting terminated
14.线程中常用的方法:
join():当线程A创建并调用了线程B,线程B调用了join方法的时候,线程A会挂起,直到线程B执行完成以后才会继续执行。(串联)join(long min)
setDaemon(true):线程A调用A.setDaemon(true)就是将线程A设置为守护线程
setUncaughtExceptionHandler(new ExceptionDemo()):用来捕获非运行时异常
例子:
public class ExceptionDemo implements UncaughtExceptionHandler{

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		System.out.println(t.getName());
		System.out.println(e.getMessage());
	}
	
	public static void main(String[] args) {
		Thread d=new Thread(new Current());
		d.setUncaughtExceptionHandler(new ExceptionDemo());
		d.start();
	}

}
class Current implements Runnable{
	@Override
	public void run() {
		System.out.println(Integer.parseInt("BANC"));
	}
}

15ThreadLocal使用:属性线程私有化

public class ThreadLocalDemo implements Runnable{
	private Date date2=new Date();
	private  ThreadLocal<Date> date=new ThreadLocal<Date>(){
		@Override
		protected Date initialValue() {
			return new Date();
		}
		
	};
	@Override
	public void run() {
		System.out.println("date2"+date2);
		System.out.println(date.get());
	}
	public static void main(String[] args) {
		ThreadLocalDemo td=new ThreadLocalDemo();
		for(int i=0;i<4;i++){
			new Thread(td).start();
			try {
				Thread.currentThread().sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
输出:
date2Thu Mar 19 15:44:49 CST 2015
Thu Mar 19 15:44:49 CST 2015
date2Thu Mar 19 15:44:49 CST 2015
Thu Mar 19 15:44:51 CST 2015
date2Thu Mar 19 15:44:49 CST 2015
Thu Mar 19 15:44:53 CST 2015
date2Thu Mar 19 15:44:49 CST 2015
Thu Mar 19 15:44:55 CST 2015
//输出很明显

		
-------------性能和伸缩性---------------------
并发导致的性能影响因素:
1.上下文切换	应用程序,操作系统,JVM都需要使用同一个CPU,就需要协调数据,导致性能开销
2.内存同步  (影响较小现在JVM会对代码进行优化,对于单线程执行的代码会去掉同步锁,对于集中处理可能方法粒度加快操作等)
3.阻塞(存在锁竞争,导致操作系统上下文切换)

减少锁的竞争:(减少锁持有的时间,降低锁的请求频率,使用带有协调机制的独占锁)
1.缩小锁的范围(快进快出)对于那些和同步无关的代码,尽量放到同步代码块的外面,尤其一些i/o操作,计算逻辑大的
2.减小锁的粒度(锁分解) 假如我们有2个集合,都进行add操作,我们完全可以定义两把锁,各自add使用各自的锁(保证原子性的前提下)。
3.锁分段:就是定义一组锁,根据一定的逻辑计算,每个线程访问对应的锁
exmaple:
private final Object[] locks=new Object[16];
private final int n=16;
synchronized(lock[i%n]){...} 
4.替代独占锁
使用并发容器,读写锁,不可变对象和原子变量等
5.不要使用对象池(虽然可以对对象进行重复使用,减少GC回收性能,但是在并发环境中,可能因为操作同一个对象导致阻塞)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值