并发编程

串行和并行:
  串行:一个线程在处理操作
  并行:多个线程在处理同一个操作
什么叫做并发编程:在多线程环境下,应用程序的执行
并发编程的目的:充分运用到资源,提高程序的效率

什么情况下用到并发编程:
  1.在线程阻塞时,导致应用程序停止
  2.处理任务时间过长时,可以创建子任务,来进行分段处理
  3.间断任务执行


一.并发编程中待解决的问题
  1.并发编程中频繁上下文切换的问题
    频繁上下文切换,可能会带来一定的性能开销
    如何减少上下文性能开销:
      1.无锁并发编程
      2.CAS
      3.使用最少线程数量
      4.协程:在单线程环境下进行多任务的调度,可以在多任务之间进行任务切换


  2.并发编程中死锁问题
      多个线程在抢占资源,但是抢占过程当中资源如果被占用,会造成阻塞,如果多个线程互抢资源时,就会造成死锁情况,死锁会导致应用程序的阻塞

  案例: 

  

public class DeadLockDemo {
	//资源
	private static final Object HAIR_A=new Object();
	private static final Object HAIR_B=new Object();

	public static void main(String[] args) {
		//第一个人
		new Thread(()->{
			//护住自己的头发
			synchronized (HAIR_A){
				System.out.println("第一个人护住自己的头发,准备薅第二个人的头发");
				//延迟时间
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//薅第二个人的头发
				synchronized (HAIR_B){
					System.out.println("第一个人薅到了第二个人的头发");
				}
			}
		}).start();
		//第二个人
		new Thread(()->{
			//护住自己的头发
			synchronized (HAIR_B){
				System.out.println("第二个人护住自己的头发,准备薅第一个人的头发");
				//延迟时间
				try {
					Thread.sleep(100);      //当前线程休眠,让渡CPU资源
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//薅第一个人的头发
				synchronized (HAIR_A){
					System.out.println("第二个人薅到了第一个人的头发");
				}
			}
		}).start();
	}
}

  

    如何预防死锁问题:
      1.破坏请求和保持条件:在申请资源时,一次性将资源都申请到
      2.破坏不可占用条件:抢占资源如何不满足,那就释放所有资源,以后如果再需要则再次申请即可
      3.破坏循环等待条件

  3.线程安全问题
    多个线程同时操作同一个资源,可能会造成资源数据不安全问题

    示例:

      

public class UnsafeThread {
	//资源
	private static int num=0;
		//计算线程数量
		private static CountDownLatch countDownLatch=new CountDownLatch(10);
		//对资源进行操作
		public static void inCreate(){
			num++;
		}


		public static void main(String[] args) throws InterruptedException {
			for (int i = 0 ; i < 10 ; i++ ){
				new Thread(()->{
					for (int j = 0 ; j < 100; j++){
						inCreate();
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					//每一个线程执行完毕,让计数-1
					countDownLatch.countDown();
				}).start();
			}
			//等待计数器为0或者小于0执行await下面代码
			countDownLatch.await();
			System.out.println(num);
		}
	}
}

  解决线程不安全问题:

public class UnsafeThread {
	//资源
	private static int num=0;
	//计算线程数量
	private static CountDownLatch countDownLatch=new CountDownLatch(10);
	private static ReentrantLock reentrantLock = new ReentrantLock();

	//对资源进行操作
	public static  void inCreate(){

		//上锁
		reentrantLock.lock();
		num++;
		reentrantLock.unlock();
	}
	
	public static synchronized void inCreate(){
		//上锁		
		num++;		
	}
	
	public static synchronized void inCreate(){
		//上锁
		synchronized(UnsafeThread.class){
			num++;
		}
	}


	public static void main(String[] args) throws InterruptedException {
		for (int i = 0 ; i < 10 ; i++ ){
			new Thread(()->{
				for (int j = 0 ; j < 100; j++){
					inCreate();
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				//每一个线程执行完毕,让计数-1
				countDownLatch.countDown();
			}).start();

		}
		//等待计数器为0或者小于0执行await下面代码
		countDownLatch.await();
		//获取到当前计数器中的线程数量
		/*while (true){
			if(countDownLatch.getCount()<=5){
				System.out.println(num);
				break;
			}
		}*/
		System.out.println(num);


	}
}

  

posted @ 2020-03-18 14:46  EXTRA·  阅读(111)  评论(0编辑  收藏  举报