什么是多线程?
首先理解什么是线程,线程是程序的执行路径,是程序的控制单元。一个进程会有一个或多个线程,当一个进程有多个执行路径,该执行方式就是多线程。
创建线程的方法?
继承Thread类,重写run()方法。
实现Runnable接口,重写run()方法。
实现Callable接口,重写call()方法。
线程的生命周期
创建(new)
就绪(Runnable):线程准备运行,等待cpu调度。
运行(Running):线程的代码块正在执行。
阻塞(Blocked)
死亡(Dead)
同步和异步
同步:线程A需要请求某资源,但是此资源正在被线程B使用,此时线程A需等待线程B执行完释放资源后再执行,这就是同步。
异步:异步与同步相对,线程B可以不用等待线程A释放资源仍可以执行。
在多线程的环境中,经常会碰到数据的共享问题,即当多个线程需要访问同一个资源时,它们需要以某种顺序来确保该资源在某一时刻只能被一 个线程使用,否则,程序的运行结果将会是不可预料的,在这种情况下就必须对数据进行同步
线程同步的实现方式
同步方法
即有 synchronized 关键字修饰的方法。
同步代码块
即有 synchronized 关键字修饰的语句块。
同步是一种高开销的操作,因此应该尽量减少同步的内容。 通常没有必要同步整个方法,使用 synchronized 代码块同步关键代码即可
使用特殊域变量(volatile)实现线程同步
使用重入锁实现线程同步
什么是死锁?如何避免死锁?
死锁:多个线程因抢占资源造成线程的无限等待的问题。
如何避免:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。
线程方法
sleep()方法:使当前线程进入睡眠状态,等待一定的时间之后,自动醒来进入到可运行状态,它没有释放锁
wait()方法:使当前线程进入阻塞状态,此方法必须先获取锁,即必须在同步方法或同步代码块中使用,它会释放锁,一旦一个对象调用了 wait 方法,必须要采用 notify()和 notifyAll()方法唤醒该进程
join()方法:线程强制执行,t1和t2两个线程,如果在t1线程里面调用了t2.join(),则t1线程会进行等待状态,t2运行结束以后,才会继续运行t1。
yield()方法:线程礼让,当前正在执行线程停下来一下,把执行机会让给别的在等待的线程,自己回到等待的就绪队列里面
什么是守护线程?
守护线程是个服务线程,准确的来说是服务其他的线程。Java中线程分为两种
守护线程:比如垃圾回收线程,就是最典型的守护线程。
用户线程,就是应用程序里的自定义线程。
守护线程,专门用于服务其他的线程,如果其他的线程(即用户自定义线程)都执行完毕,连 main 线程也 执行完毕,那么 jvm 就会退出(即停止运行)——此时,连 jvm 都停止运行了,守护线程当然也就停止执行了。
什么是悲观锁和乐观锁?怎么实现?
悲观锁:
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁, 这样别人想拿这个数据就会阻塞直到它拿到锁。
实现方式:
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁, 表锁等,读锁(共享锁),写锁(排他锁)等,都是在做操作之前先上锁。
Java 里面的同步原语 synchronized 关键字。
乐观锁:
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。
实现方式:
CAS
添加版本号:一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会+1。当线程A要更新数据值时,在读取数据的同时也会读取version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功
1832

被折叠的 条评论
为什么被折叠?



