java多线程

 1.并行和并发有什么区别?

并发(concurrency)和并行(parallellism)是:

解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
解释三:在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群
所以并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。
 

2.线程和进程的区别?

线程的基本概念: 线程是进程中执行运算的最小单位,是进程的一个实体,是被系统独立调度和分配的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但他可以在同属一个进程的其他线程中共享进程中的全部资源。一个线程可以创建和撤销另一个线程,同一进程中的多个线程之间可以并发执行。

进程: 每一个进程都拥有独立的代码和数据空间,进程的切换会有较大的开销,一个进程包含1--n个线程

线程: 同一类线程共享代码和数据空间,每一个线程都有独立运行栈和程序的计数器,线程切换开销小。

线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止

(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位

    (2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行

    (3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.

    (4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。

3.守护线程是什么?

守护线程,专门用于服务其余线程的,如果其他的线程都执行完毕,连main线程都执行完毕了,那么jvm就会退出(即停止运行)

换一种说法,如果有用户自定义线程存在的话,jvm 就不会退出--此时,守护线程也不能退出,也就是它还要运行。进行垃圾回收

4..说一下 runnable 和 callable 有什么区别?

相同点:1)两者都可以用来编写多线程程序

2)两者都需要调用Thread.start() 启动多线程

不同: 1)实现Callable 接口的任务线程能返回执行结果;实现Runnable接口的任务线程不返回结果

2)Callable 接口的call() 方法允许抛出异常,而runnable 接口的run 方法的一场只能在内部消化,,不允许上抛

说说Runnable与Callable - 每天一点 - 博客园

5线程有哪些状态?

新建、就绪、运行、阻塞、死亡

6.sleep() 和 wait() 有什么区别?

1.sleep 来自于thread类,wait 来自于Object 类。sleep 方法属于Thread 类中的静态方法,wait属于Object的成员方法

2.sleep  不会释放锁,释放资源。wait,释放锁,释放资源

3.wait、notify,notifyAll 只允许在同步控制方法或者同步控制块里面使用,而sleep 可以在任意地方使用

4.sleep 方法需要捕获InterruptedException 而wait、notify 不需要捕获异常

7.notify()和 notifyAll()有什么区别?

notify 唤醒等待的线程,并不确定唤醒的是哪一个线程

notifyAll 唤醒所有等待的线程。

  • 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁
  • 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
  • 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

8.线程的 run()和 start()有什么区别?

1)方法的定义: start 在thread 中定义,run 在runnable 中定义,必须在实现类中重写

2) 新线程的创建:在调用start 方法的时间会创建新的线程,run 方法的时间则不会

3)start 不能多次调用,否则会抛出 IllegalStateException ,run方法可以重复调用,因为它只是一种正常的方法调用

9创建线程池有哪几种方式

  • 通过Executors工厂方法创建
  • 通过new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue)自定义创建

newSingleThreadPool 创建单线程的线程池

newFixedThreadPool  创建固定大小的线程池

newCachedThreadPool 创建一个可缓存的线程池

newScheduledThreadPool 创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求。

10线程池都有哪些状态? 

1.RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。线程池的初始化状态是RUNNING。线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0。

2.SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。调用线程池的shutdown()方法时,线程池由RUNNING -> SHUTDOWN。

3.STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。调用线程池的shutdownNow()方法时,线程池由(RUNNING or SHUTDOWN ) -> STOP。

4.TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。因为terminated()在ThreadPoolExecutor类中是空的,所以用户想在线程池变为TIDYING时进行相应的处理;可以通过重载terminated()函数来实现。 

当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。

当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

5.TERMINATED:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。
11.线程池中 submit()和 execute()方法有什么区别?

execute() 参数 Runnable ;submit() 参数 (Runnable) 或 (Runnable 和 结果 T) 或 (Callable)
execute() 没有返回值;而 submit() 有返回值
submit() 的返回值 Future 调用get方法时,可以捕获处理异常

12..在 java 程序中怎么保证多线程的运行安全?

线程的安全性问题体现在:

原子性:一个或者多个操作在 CPU 执行的过程中不被中断的特性
可见性:一个线程对共享变量的修改,另外一个线程能够立刻看到
有序性:程序执行的顺序按照代码的先后顺序执行
 

导致原因:

缓存导致的可见性问题
线程切换带来的原子性问题
编译优化带来的有序性问题
 

解决办法:

JDK Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题
synchronized、volatile、LOCK,可以解决可见性问题
Happens-Before 规则可以解决有序性问题

Happens-Before 规则如下:

程序次序规则:在一个线程内,按照程序控制流顺序,书写在前面的操作先行发生于书写在后面的操作
管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作
volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作
线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作
线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测
线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始
 
java 程序中怎么保证多线程的运行安全?_ConstXiong-CSDN博客_在java程序中怎么保证多线程的运行安全

13多线程锁的升级原理是什么?

锁的级别

无锁-》偏向锁-》轻量级锁-》重量级锁

没有优化以前,synchronized是重量级锁(悲观锁),使用 wait 和 notify、notifyAll 来切换线程状态非常消耗系统资源;线程的挂起和唤醒间隔很短暂,这样很浪费资源,影响性能。所以 JVM 对 synchronized 关键字进行了优化,把锁分为 无锁、偏向锁、轻量级锁、重量级锁 状态。

偏向锁:对象的代码一直被同一线程执行,不存在多个线程竞争,该线程在后续的执行中自动获取锁,降低获取锁带来的性能开销。偏向锁,指的就是偏向第一个加锁线程,该线程是不会主动释放偏向锁的,只有当其他线程尝试竞争偏向锁才会被释放。

偏向锁的撤销,需要在某个时间点上没有字节码正在执行时,先暂停拥有偏向锁的线程,然后判断锁对象是否处于被锁定状态。如果线程不处于活动状态,则将对象头设置成无锁状态,并撤销偏向锁;

如果线程处于活动状态,升级为轻量级锁的状态。

轻量级锁:轻量级锁是指当锁是偏向锁的时候,被第二个线程 B 所访问,此时偏向锁就会升级为轻量级锁,线程 B 会通过自旋的形式尝试获取锁,线程不会阻塞,从而提高性能。

当前只有一个等待线程,则该线程将通过自旋进行等待。但是当自旋超过一定的次数时,轻量级锁便会升级为重量级锁;当一个线程已持有锁,另一个线程在自旋,而此时又有第三个线程来访时,轻量级锁也会升级为重量级锁。

重量级锁:指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。

重量级锁通过对象内部的监视器(monitor)实现,而其中 monitor 的本质是依赖于底层操作系统的 Mutex Lock 实现,操作系统实现线程之间的切换需要从用户态切换到内核态,切换成本非常高。

锁状态对比:

14.什么是死锁?

两个线程在执行过程中,因为竞争资源或者彼此间通信造成的阻塞的现象。

15.怎么防止死锁?

1)尽量使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁

2) 尽量使用concurrent 并发类代替自己手写锁

3)尽量降低锁的使用粒度,尽量不要几个功能同一把锁

4)尽量减少同步代码块

16.ThreadLocal 是什么?有哪些使用场景?

threadLocal 是线程本地存储,在每个线程中都创建一个ThreadLocalMap对象,每个线程都可以访问自己内部的ThreadLocalMapd对象的Value,通过这种方式,避免了资源在多线程之间共享。

经典的使用场景是为每一个线程分配一个Jdbc 链接Connection ,这样就可以保证每一个线程都在各自的Connection上进行数据库的操作,不会出现线程A关闭线程B的Connection,还有Session 管理等问题

17.说一下 synchronized 底层实现原理?(不太对的样子)

synchronized 译为同步,是java的内建锁,用来保证线程安全,是解决并发问题的一种重要手段,synchronized可以保证在多个线程中,每次仅有一个线程访问共享资源。

  • 同步代码块是通过 monitorenter 和 monitorexit 指令获取线程的执行权
  • 同步方法通过加 ACC_SYNCHRONIZED 标识实现线程的执行权的控制

18.synchronized 和 volatile 的区别是什么?

  • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
  • volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
  • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
  • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

19.synchronized 和 Lock 有什么区别?

synchronized 是java 语言的关键字,因此是内置特性。lock 是一个类,通过这个类可以实现同步访问

Lock 和synchronized 有非常大的一点不同,采用synchronized 不需要用户去手动释放锁,当synchronized方法或者着synchronized代码块执行完之后,系统会自动让线程释放锁的占用,而Lock则必须用户手动去释放锁,如果没有,则会出现死锁现象。

区别: 1.用法不一样。synchronized 既可以加在方法上,也可以加在特定的代码块上,括号总表示需要锁的对象,而lock需要显示地指定起始位置和终止位置。synchronized 是托管给Jvm 执行的,Lock 锁定是通过代码实现的。

2.在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈的试卷,Lock性能是要远远优先于synchronized的,所以说,在具体的时间要根据适当情况选择。

3.锁的机制不同: synchronized 获得缩合释放锁的方式都是在块结构中,而且是自动释放锁,而Lock则需要开发人员手动去释放,并且必须在finnally中释放,不然会引发死锁问题

4.lock是一个接口,而synchronized 是java中的关键字,synchronized是内置的语言实现

5.synchronized发生异常,会自动释放占有的锁,而lock发生异常,则需要在unlock中释放锁,否则会发生死锁。

6.lock 可以让等待锁的线程响应中断,通过lock可以知道有没有成功获取锁,而synchronized 无法办到。

20..synchronized 和 ReentrantLock 区别是什么?

reentrantLock 是什么 以对象的方式来操作对象锁.相对于sychronized需要在finally中去释放锁 

相似点:
这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的(操作系统需要在用户态与内核态之间来回切换,代价很高,不过可以通过对锁优化进行改善)。

功能区别:
这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成

便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。

锁的细粒度和灵活度:很明显ReenTrantLock优于Synchronized

性能的区别:
在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。
Synchronized与ReentrantLock区别总结(简单粗暴,一目了然)_zxd8080666的博客-CSDN博客_reentrantlock与synchronized区别

21.说一下 atomic 的原理?

https://mp.weixin.qq.comaw6OXC9wkxH42rCywNd7yQ/s/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值