线程

线程与进程
进程是应用程序的执行单元,线程是进程的执行单元;
并行与并发
并行:同一时刻发生多件事情;并发:同一时间段发生多件事情;
多线程原理和创建方式
Java中的多线程的原理是抢占式调度,同一个时刻JVM只能执行一个线程;
Java中创建多线程的方式:继承Thread类,及实现任务类对象;
继承:创建一个Thread子类,重写run方法(任务代码),在测试类中创建子类对象,调用start()方法;
实现任务接口:创建一个实现类接口,实现Runnable接口,重写run方法,在测试类中创建实现类对象,将其作为参数传入Thread构造方法中,利用Thread的对象调用start()方法;
多线程实现任务接口的好处
1.任务可以共享,重复利用
2.任务与线程分开,方便维护和管理
3.接口可以多实现,解决单继承的弊端
4.实现类接口(Runnable 和Callable)可以放在线程池中,而继承类不可以
线程安全问题产生的原因
线程调度是抢占式的,可能产生一个线程在执行任务的时候,会被另一个线程打断,产生”数据混乱”的问题;如多个窗口同时卖票,多个线程可能卖出同样的票,或者产生负数票;
线程安全:在某个时间点上,当大量线程访问同一资源时,由于多线程运行机制的原因,可能会导致被访问的资源出现”数据污染”的问题
高并发:在某个时间点上,有多个线程访问同一资源;如:天猫购物节,12306的在线购票
多线程安全性问题的特性
1.可见性:线程在执行任务时,会在主内存中复制一份对象在线程开辟的堆内存中,会导致线程对对象进行修改后传入的值不会及时传递给其他线程共享
2.有序性:多线程情况下,代码会进行重排,可能会对另一个线程访问的结果产生影响,使结果偏离期望
3.原子性:是指在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断,要么所有的操作都不执行,多个操作是一个不可以分割的整体。
解决多线程安全性的方式
解决可见性和有序性问题,可以使用volatile关键字,它只能修饰"成员变量",它能强制线程每次从主内存获取值,并能保证此变量不会被编译器优化;
解决可见性,有序性和原子性:使用锁synchronized修饰代码块和方法,或者使用lock锁对象进行lock()和unlock()操作;使用原子类:如AtomicInteger,AtomicIntegerArray,CopyOnWriteArrayList等
原子类的运行原理CAS(Compare And Set),原子类创建的对象,会执行CAS,当线程进行取值操作时,会与主内存中的值进行比较,如果相等,则会执行变量操作,并把操作后的值写进主内存,如果不相等,则重新取值;
线程相关类的作用及方法
CountDownLatch类允许一个或多个线程等待其他线程完成操作。传入计数器(初始化计数器对象),countDown()计数器减1,await()进行等待,当计数器为0时执行后续代码;
CyclicBarrier类是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。需要传入的参数是达到屏障的线程数量和达到屏障后需要执行的Runnable任务对象;
Semaphor类主要作用是控制线程的并发数量。传入参数是许可线程数量,acquire()代表获得许可,release()代表释放许可;
Exchanger类(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。空参构造方法,exchanger()参数是要交换的数据,返回值是对方线程传递的数据;
线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
线程池的工作原理
1.创建线程池,初始化指定数量的线程
2.提交任务到线程池:如果有空闲的线程,就会随机分配空闲的线程来执行任务;如果没有空闲的线程,那么任务就会在任务队列中等待,当有空闲线程的时候,就会随机分配空闲的线程来执行任务
线程池的好处
1.降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2.提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
3.提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
线程池的使用步骤
常用方式是采用Executors类下面的newFixedThreadPool(int nThreads)返回线程池对象(ExecutorService)
使用线程池中线程对象的步骤:
使用步骤:
1.创建线程池对象。
2.创建Runnable接口子类对象。(task)
3.提交Runnable接口子类对象。(take task)
4.关闭线程池(一般不做)。
悲观锁Synchronized与乐观锁CAS(Compare And Swap)
1.悲观锁Synchronized是从悲观的角度出发:
总是假设最坏的情况,每次拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其他线程阻塞,用完后再把资源转让其他线程).因此Synchronized我们也将其称之为悲观锁.jdk中的ReentranLock也是一种悲观锁
2.CAS是从乐观的角度出发:
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会去判断一下在此期间别人有没有去更新这个数据.
CAS这种机制我们也可以将其称之为乐观锁
死锁产生的原因
多条线程,多把锁,造成线程A获取到了线程B需要的锁,而线程B获取到了线程A需要的锁,并且都没有释放

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值