#sleep | wait 关于释放锁和线程的区别
- sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,将执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
- wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态
#Thread 的问题
- new Thread的弊端如下:
- 每次new Thread新建对象性能差。
- 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
- 缺乏更多功能,如定时执行、定期执行、线程中断。
- 相比new Thread,Java提供的四种线程池的好处在于:
- 重用存在的线程,减少对象创建、消亡的开销,性能佳。
- 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
- 提供定时执行、定期执行、单线程、并发数控制等功能。
#线程池 ##线程池按以下行为执行任务
- 当线程数小于核心线程数时,创建线程。
- 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
- 当线程数大于等于核心线程数,且任务队列已满
- 若线程数小于最大线程数,创建线程
- 若线程数等于最大线程数,抛出异常,拒绝任务
##Java通过Executors提供四种线程池,分别为:
- newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool 创建一个定时线程池,支持定时及周期性任务执行。
- newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序( FIFO, LIFO, 优先级)执行
- newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。由于线程池无限大,newCachedThreadPool 大家一般不用就是这样的原因,因为它的最大值是在初始化的时候设置为 Integer.MAX_VALUE,一般来说机器都没那么大内存给它不断使用
###newScheduleThreadPool Demo
public static void testScheduledThreadPool() { ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); for (int i = 0; i < 10; i++) { pool.schedule(new Runnable() { @Override public void run() { try { Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + "is running!"); } catch (InterruptedException e) { e.printStackTrace(); } } }, 3, TimeUnit.SECONDS); } pool.shutdown(); }
pool-1-thread-1is running!pool-1-thread-2is running!pool-1-thread-1is running!pool-1-thread-2is running!pool-1-thread-1is running!pool-1-thread-2is running!pool-1-thread-1is running!pool-1-thread-2is running!pool-1-thread-1is running!pool-1-thread-2is running!
Executor.submit() Demo
public static void testExecutorSubmitMethod() { ExecutorService pool = Executors.newFixedThreadPool(2); Futurefuture[] = new Future[10]; for (int i = 0; i < 10; i++) { future[i] = pool.submit(new Callable () { @Override public String call() throws Exception { Thread.sleep(10); return Thread.currentThread().getName(); } }); } for (Future f : future) { try { String result = f.get(); System.out.println(result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } pool.shutdown(); }
pool-1-thread-1pool-1-thread-2pool-1-thread-1pool-1-thread-2pool-1-thread-1pool-1-thread-2pool-1-thread-1pool-1-thread-2pool-1-thread-1pool-1-thread-2
#Lock | ReadWriteLock 比较好的模板总结:
此外,注意搭配!
- synchronized { wait , notify|notifyAll}
- Lock {condition.await(), condition.signal()|condition.signalAll()}
#CyclicBarrier 适合执行子任务完了再执行主任务的情况 ##Demo
package BarrierPackage;import java.util.concurrent.CyclicBarrier;/** * Created by pinker on 17-2-23. */public class CycliCarrierDemo { public static void main(String[] args) { CyclicBarrier pool=new CyclicBarrier(7,new MainTask()); for(int i=0;i<7;i++){ new Thread(new SubTask(pool)).start(); } }}
package BarrierPackage;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;/** * Created by pinker on 17-2-24. */public class SubTask implements Runnable { private CyclicBarrier barrier; public SubTask(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { try { Thread.sleep(1000);//模仿子任务执行时间! } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "执行完毕,已通知主任务!"); try { barrier.await();//通知障碍器已经完成! } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }}
Thread-0执行完毕,已通知主任务!Thread-1执行完毕,已通知主任务!Thread-2执行完毕,已通知主任务!Thread-3执行完毕,已通知主任务!Thread-4执行完毕,已通知主任务!Thread-5执行完毕,已通知主任务!Thread-6执行完毕,已通知主任务!主任务开始执行了!