串行和并行:
串行:一个线程在处理操作
并行:多个线程在处理同一个操作
什么叫做并发编程:在多线程环境下,应用程序的执行
并发编程的目的:充分运用到资源,提高程序的效率
什么情况下用到并发编程:
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); } }