Java并发(1)API

一些问题:说说wait(),sleep(),yield()这3个方法、notify(),notifyAll()各自可能出现的问题、说说copyOnWrite机制以及适用场景、说说AQS、阻塞队列的实现原理、线程池的4种实现,原理。

与线程相关的几个基本方法 :

     wait():Object类的final native方法,抛中断异常。在一个线程中调用某个对象A的wait()方法,当前线程立即放弃对象锁,转到阻塞队列,当在另一个线程中调用A对象的notify()或notifyAll()时该线程被唤醒,准备从新获取锁。

    sleep():Thread类的静态native方法,抛中断异常。休眠。在一个线程中调用sleep()方法,当前线程休眠指定时间后直接进入就绪状态,不会放弃对象锁。

    yield():Thread类的静态native方法。屈服/让步。在一个线程中调用yield()方法,当前线程立即放弃CPU直接进入就绪状态,等待被CPU调度,不会放弃对象锁。

    notify():Object类的final native方法。在一个线程中调用一个某个对象A的notify()方法,从等待A的阻塞队列中所有线程中随机唤醒一个,可能造成信号丢失问题;当前线程不会立即放弃对象锁;需要通过退出同步代码块(代码执行完),或者调用wait()显示放弃对象锁。

    notifyAll():Object类的final native方法。在一个线程中调用一个某个对象A的notifyAll()方法,会唤醒所有等待A的线程(设N个),然后这N个线程去竞争同一个锁,最多只有一个线程可以得到锁,其它线程又回到阻塞状态(之前是等待A对象的通知,现在是竞争不到锁而阻塞,造成过早唤醒)。这意味着一次notifyAll()操作可能带来大量的上下文切换(N比较大),同时有大量竞争锁的请求。这对于频繁的唤醒操作而言性能上是一种灾难。可以通过ReentrantLock与Condition实现选择性通知。

    sleep()会给其它线程运行的机会,不考虑线程的优先级;yield()只会给同优先级或更高优先级的线程运行的机会,当然也包括自己。sleep()会抛出异常,yield()不抛;sleep()比yield()具有更好的移植性,不能依靠yield()来提高程序的并发性能。

    join():在一个线程里调用另一个线程对象的join()方法,会导致当前线程阻塞。不要混淆线程执行体和线程对象。看Thread类源码知,join()通过wait()实现,故join()会释放锁。

    public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {//当线程对象仍是活着的时候
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

若在A线程中调用B线程的join()方法,只有当B线程执行完毕时,A线程才能继续执行(第一个分支)。

    isAlive() :检测线程对象的状态,当前线程对象已经start()还没die就算活着

CopyOnWrite写时复制机制

    写线程在副本上写,这样在写的同时读线程还可以读,使用于读多写少的场景。典型实现有copyOnWriteArraylist数组。

抽象队列同步器AQS

    抽象队列同步器,它定义了一套同步框架,许多同步类都依赖于它,如常用的ReenterLock/ReenterReadWriteLock/Semaphore/CountDownLatch。

    1.维护了一个volatile int state(代表同步状态)以及一个CLH队列(FIFO)和若干个Condition队列。AQS提供了三个核心的final方法实现对state变量的管理:getState()获取当前同步状态、setState()设置当前同步状态、compareAndSetState()通过CAS更新当前同步状态。

    2.AQS采用了模板方法模式,有5个protected方法是延迟给子类实现的,子类可以选择只实现其中的部分方法。子类被推荐定义为自定义同步组件的静态内部类。

    3.原理图。



        4.Condition的实现原理。Condition依赖lock实现等待/通知机制,Condition对象是由lock对象创建出来的(lock.new Condition)。AQS的ConditionObject内部类是Condition接口的实现类。



阻塞队列

    阻塞队列是一个支持两个附加操作的队列(FIFO)。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。试图向已满队列中添加元素会导致线程阻塞,试图向空队列中提取元素会导致线程阻塞。    JDK7提供了7个阻塞队列实现类。

    顶层接口:public interface BlockingQueue<E> extends Queue<E> {...}

    子接口:   public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {...}

ThreadLocal类

    为每个线程保存自己的一个私有属性。

线程池

    Executors是线程池的工厂类,方便快捷的创建很多线程池。主要有4类线程池。

    创建一个只含一个线程的线程池Executors.newSingelThreadExecutor();

    创建一个固定大小的线程池Executors.newFixedThreadPool();

    创建一个大小的伸缩的线程池Executors.newCachedThreadPool();

    创建一个指定延迟时间或可周期性执行任务的线程池Executors.newScheduledThreadPool()。

   //内部代码实现:
     public ThreadPoolExecutor(int corePoolSize,//核心池大小
                              int maximumPoolSize,//线程池临时允许最大线程数
                              long keepAliveTime,//临时线程最多多久没有执行任务就会被销毁
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,/线程等待池,即待执行的任务序列
                              ThreadFactory threadFactory,//创建线程的工厂类
                              RejectedExecutionHandler handler) {//当任务序列满时,采用何种方式拒绝一个任务
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

    线程池任务拒绝策略RejectedExecutionHandler:

        1.AbortPolicy:直接抛出异常。

        2.CallerRunsPolicy:直接让调用者所在线程来运行任务。

        3.DiscardOldestPolicy:丢掉队列里等待最久的一个任务,并尝试执行该任务。

        4.DiscardPolicy:不处理,直接丢弃掉。

    线程池的好处:

        1.重复利用已经创建的线程,降低线程创建和线程销毁的开销。

        2.提高响应速度,减少了等待线程创建的时间

        3.提高了线程的可管理性。使用线程池可以对线程进行统一的 分配,调优和监控。

    对于CPU密集型任务,配置尽量小的线程数Ncpu+1;对于IO密集型任务,需要cpu的时间比较少,大部分时间在IO,可以配置尽量多的线程数2*Ncpu。

Fork/Join框架

    Future任务机制与FutureTask:    

    API:

        public class FutureTask<V> implements RunnableFuture<V> {...}//FutureTask类实现了RunnableFuture接口

      public interface RunnableFuture<V> extends Runnable, Future<V> {//RunnableFuture继承了Runnable接口和Future接口
            void run();

        }

    Fork/Join将一个大任务Fork成若干个相互独立,不相依赖的子问题,知道所有子问题得到解决。

//使线程具有有序性
//顺序打印A B C D A B C D...
public class WaitNotifyDemo {
	public static void main(String[] args) {
		int totalNumber=4;
		final Mylock sharedObj=new Mylock();
		for(int i=0;i<totalNumber;i++){
			new MyThreadV(sharedObj, (char)('A'+i), i, totalNumber).start();;
		}
	}
}
class MyThreadV extends Thread{
	private Mylock sharedObj;
	private char mark;
	private int number;//该线程对象序号
	private int total;//总序号数
	public MyThreadV(Mylock obj,char mark,int number,int total) {
		this.sharedObj=obj;
		this.mark=mark;
		this.number=number;
		this.total=total;
	}
	@Override
	public void run() {
		while(true){
			try {
				sleep(200);
				synchronized (sharedObj) {
					if(sharedObj.count%total==number){
						System.out.print(mark+" ");
						if(sharedObj.count%total==total-1){
							System.out.println();
						}
						sharedObj.count++;
						sharedObj.notifyAll();//key1
					}else{
						sharedObj.wait();//key2没有轮到该线程,放弃处理机,释放对象锁,
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
class Mylock{
	public int count;
	public Mylock() {
		this.count=0;
	}
}
public class CountDownLaunchDemo {
	public static void main(String[] args) throws InterruptedException {
		int subTask=9;
		CountDownLatch latch=new CountDownLatch(subTask);//key1
		for(int i=0;i<subTask;i++){
			new MyThread(latch, i).start();
		}
		latch.await();//key3
		System.out.println("所有子任务结束,主任务开始继续执行");
	}
}
class MyThread extends Thread{
	CountDownLatch latch;
	int i;
	public  MyThread(CountDownLatch latch,int i){
		this.latch=latch;
		this.i=i;
	}
	@Override
	public void run() {
			try {
				System.out.println("子任务"+i+"开始");
				Thread.sleep(1000);//模拟子任务工作
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("子任务"+i+"完毕");
			latch.countDown();//key2

	}
}
public class CyclicBarrierDemo {
	public static void main(String[] args) {
		int task=9;
		CyclicBarrier cyclicBarrier=new CyclicBarrier(task);
		for(int i=0;i<task;i++){
			new MythreadII(cyclicBarrier, i).start();
		}
	}
}
class MythreadII extends Thread{
	CyclicBarrier cyclicBarrier;
	int index;//任务编号
	public MythreadII(CyclicBarrier cyclicBarrier,int i) {
		this.cyclicBarrier=cyclicBarrier;
		this.index=i;
	}
	@Override
	public void run() {
		try {
			Thread.sleep(1000);
			System.out.println("子任务:"+index+"第一阶段完成...");
			cyclicBarrier.await();//直到所有部分都已经对这个屏障执行了await()操作
			System.out.println("子任务:"+index+"开始第二阶段");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
public class SemaphoreDemo {
	public static void main(String[] args) {
		//有10个人要求进行服务,服务器最多只能同时服务3个人
		int maxCapcity=3;
		int task=10;
		Semaphore semaphore=new Semaphore(maxCapcity);//key1,指定许可量
		for(int i=0;i<task;i++){
			new MyThreadI(semaphore, i).start();
		}
	}
}
class MyThreadI extends Thread{
	Semaphore semaphore;
	int index;//编号
	public MyThreadI(Semaphore semaphore,int i){
		this.semaphore=semaphore;
		this.index=i;
	}
	@Override
	public void run() {
		System.out.println("用户"+index+"连接上服务器:");
		try {
			semaphore.acquire();//key1 请求获取一个许可,获取前将一直阻塞
			System.out.println("用户"+index+"开始访问后台程序");
			Thread.sleep(1000);//模拟服务
			System.out.println("用户"+index+"访问结束。");
			semaphore.release();//归还一个许可
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

其它:

模板方法模式:在父类中定义算法骨架,将具体实现延迟到子类实现。

关于AQS与Condition,看AQS类源码。

参:

http://blog.csdn.net/qq_17438907/article/details/49049051

http://blog.csdn.net/yangdongchuan1995/article/details/78578337

http://ifeve.com/java-blocking-queue/

https://www.cnblogs.com/lnlvinso/p/4753554.html

http://ifeve.com/abstractqueuedsynchronizer-use/#more-18899

https://www.cnblogs.com/waterystone/p/4920797.html


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值