目标:
1.如何实现多线程之间的通讯
2.了解wait,notify,notifyAll() 方法
3.sleep 与 wait 的区别
4.synchronized 与 lock 接口的区别i
5.如何停止线程
6.什么是守护线程
7.join 方法
8.优先级
9.yield 方法
一、如何实现多线程之间的通讯
1.什么是多线程之间的通讯?
答:多线程之间的通讯,就是多个线程操作同一个全局变量时候,做的操作不同。如一个读,一个写。
例子:
如:一个线程做写入 用户信息操作,一个线程做读取用户信息操作。(生产消费模型)
代码示例:
创建实体类
创建连个线程
3.创建主线程
5.线程1做写的操作,线程2做读的操作。
写操作线程
读操作线程
创建线程看看效果!!
效果:
发生了线程安全问题!!!
解决办法:
在上一章节中讲到 用使用同步代码块或者锁来解决。
添加同步代码块或者锁来看看效果。
解决了数据冲突问题。那么下面我们如何做到一个线程写一个,另外一个线程读一个呢?
这里我们就用到wait,notify,notifyAll 这三个方法
二、wait,notify,notifyAll
这三个方法分别有什么作用?
wait(),notify(),notifyAll(),这三个方法是定义在object类里面的方法,用来控制线程的状态。这三个方法最终在jvm中调用是native 方法。
wait():如果对象调用了次方法,那么就会把对象的控制权交出去,然后出于等待状态
notify():如果对象调用了次方法,那么就会通知正在等待这个对象的控制权限可以继续运行,
notifyAll():如果对象调用了这个方法,那么就会通知所有等待这个对象的控制权,继续运行。
这里我们继续上面的例子:
定义一个标识:
写的线程
读的线程:
运行结果:
这样线程之间的通讯就搞定了,生产者消费者模型也是基于此类的。
三、wait(),与sleep()的区别
wait(): wait() 方法时object 类中的,如果对象调用了次方法,那么就会把对象的控制权交出去,然后出于等待状态
sleep(): sleep() 方法是,Thread 类中的方法 ,次线程进入休眠状态,但是不会把对象的控制权交出去。处于休眠状态,即 把CPU 的使用权让出去给其他线程使用。
总结:1.wait() 是object 类中的方法,而sleep()是Thread 类中的方法,
2.wait()方法会释放锁,而sleep()不会释放锁
四、lock 与synchronized 的区别
1. 什么是lock?
在 jdk1.5 之后,并发包中新增了 Lock 接口(以及相关实现类)用来实现锁功能,Lock 接口提供了与 synchronized 关键字类似的同步功能,但需要在使用时手动获取锁和释放锁。
2.创建方法
3.区别
使用lock 可以手动获取锁,手动释放锁。
synchroinzed 不能手动获取锁。释放锁。
五、如何停止线程
1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
2. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。
3. 使用interrupt方法中断线程。
总结: stop 已经过时 强制停止 会造成线程安全问题, 一般使用interrupt方法来中断线程。
六、守护线程
Java中有两种线程,一种是用户线程,另一种是守护线程。
当进程不存在或主线程停止,守护线程也会被停止。
使用setDaemon(true)方法设置为守护线程
1.为什么会出现守护线程?
很多用户喜欢强退,因为线程是互补干扰的。如果主线程关闭了,那么其他线程还在继续跑怎么办?
这就造成了守护线程。
2.守护线程的作用
当主线程停止时,守护线程也停止。
七、join() 方法
join() 方法,是让这个线程先执行。也就是让其他线程变为等待。
join(3000) 意味着先执行三秒,让其他线程等待三秒。
总结:保证线程的有序性!
八、优先级
现代操作系统基本采用时分的形式调度运行的线程,线程分配得到的时间片的多少决定了线程使用处理器资源的多少,也对应了线程优先级这个概念。在JAVA线程中,通过一个int priority来控制优先级,范围为1-10,其中10最高,默认值为5。下面是源码(基于1.8)中关于priority的一些量和方法。
注意:设置了优先级,不代表每一次都被执行,只是CPU 会有限分配。
九、Yield 方法
Thread.yield()方法的作用:暂停当前正在执行的线程,并执行其他线程。(可能没有效果)
yield()让当前正在运行的线程回到可运行状态,以允许具有相同优先级的其他线程获得运行的机会。因此,使用yield()的目的是让具有相同优先级的线程之间能够适当的轮换执行。但是,实际中无法保证yield()达到让步的目的,因为,让步的线程可能被线程调度程序再次选中。
结论:大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。