温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java基础 (14) - 多线程

发布时间:2020-08-08 02:31:32 来源:网络 阅读:215 作者:lm8751 栏目:编程语言

1.实现多线程
Thread、Runnable、Callable、ExecutorService四种方式
Runnable和Callable的区别是
1>Runnable是run() , Callable是call()。其中Runnable可以提交给Thread来包装下,Callable一般都是提交给ExecuteService和FutureTask来执行。
2>Callable能返回值和抛出异常。
3>Callable获取值时会导致所在的线程等待,直到get返回值为止,返回之前会中断当前线程。
参考
四种实现多线程方式:https://blog.csdn.net/u011480603/article/details/75332435/
Callable、Future和FutureTask :https://www.cnblogs.com/dolphin0520/p/3949310.html

2.启动线程
run() 和 start()区别
start()是真真的开启一个线程执行。(等待系统分配cpu资源)
run()只是线程的一个普通方法,只调用run(),该方法会在调用者线程进行。(不会在新线程执行)

3.停止线程
(1)使用退出标志(volatile 布尔变量),也就是当run方法完成后线程终止。
(2)使用interrupted方法阻塞线程(修改线程中断标记值) ,isInterrupted()返回线程标记值。
(3)使用stop方法强行终止线程 (这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)

4.线程异常
线程出现异常结果
(1)线程运行 ->线程处理了异常或抛出
(2)线程停止 ->发生异常线程没有捕获或没有将其抛出,此时JVM会使用Thread.getUncaughtExceptionHandler()来查询线程的UncaughtExceptionHandler并将线程和异常作为参数传递给handler的uncaughtException()方法进行处理
使用步骤
第一步:implements UncaughtExceptionHandler 自定义异常处理类
第二步:Thread t = new Thread(new ExceptionThread());
t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
t.start();

5.线程同步
synchronized方法、synchronized模块(wait/notify机制)、ReenreantLock、volatile、while轮询等方式
(1)synchronized方法
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 
内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态

(2)synchronized模块 - wait/notify机制
同步是一种高开销的操作,因此应该尽量减少同步的内容
通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可

(3)  ReenreantLock
JavaSE1.5.新增了一个java.util.concurrent包来支持同步。 
ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 
它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力
ReenreantLock类的常用方法有:
        ReentrantLock() : 创建一个ReentrantLock实例 
        lock() : 获得锁 
        unlock() : 释放锁  - finally 中执行
从上可看出 他在写法上相对synchronized 更简洁

(4) volatile
可见性 - 使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新.因此每次使用该域就要重新计算,而不是使用寄存器中的值
有序性 - java优化的时候 ,将不改变此修饰过的变量执行顺序

6.如何避免死锁?
Java多线程中的死锁 死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
    解决死锁
    https://www.cnblogs.com/android-blogs/p/5765148.html

7.常见问题
(1)wait/notify机制
以生产者和消费者为例
调用任意方法,必须在对象锁方法体中
生产者调用notify后,生产者所在线程并不会立即退出线程,得等到生产者执行完毕。消费者才有可能机会执行
消费者被唤醒后是从wait()方法(被阻塞的地方)后面执行,而不是重新从同步块开头
(2)notify和notifyAll有什么区别
notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。
notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行
(3)wait() 和 sleep()有什么不同?
sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁
释放锁资源,进入资源等待池等待
参考:https://www.cnblogs.com/hapjin/p/5492619.html
(4)Synchronized和ReentrantLock的区别
ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量,ReentrantLock比synchronized的扩展性体现在几点上:
(1)ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁
(2)ReentrantLock可以获取各种锁的信息
(3)ReentrantLock可以灵活地实现多路通知
另外,二者的锁机制其实也是不一样的。ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word

参考:https://blog.csdn.net/qq_41212104/article/details/81773717

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI