多线程 —— 代码安全以后,对线程调度的控制(等待-唤醒机制)
来源:互联网 发布:淘宝的流量钱包自动领 编辑:程序博客网 时间:2024/06/12 01:53
。导读:上一个多线程的程序,我们能保证对象的设置和打印是安全的,不会出现数据错乱和出错的情况,但是我们不能很好地控制线程的执行。我们希望的是,设置了对象以后,打印线程打印,然后再设置对象,然后再打印,如此反复。
但是多线程的执行具有随机性,我们不能这样控制线程执行。
线程1
线程2
线程1
线程2
线程1
线程2
……
但是 Java 为我们提供了“等待-唤醒”机制,通过该机制,就可以实现多线程程序好像是按照上面的方式执行一样。
1、竞争资源
public class Student { String name; Integer age; // 默认情况是没有数据的,如果是 true,就说明是有数据的 // 如果是 Boolean 默认情况下就没有初始值 // 看看自动拆箱、装箱的内容 // 我们约定:刚刚被 set 就赋值为 true,刚刚被 get 就赋值为 false boolean flag;}
2、设置对象和访问对象的线程
(1)设置对象属性的线程:如果对象的属性设置过了,就让这个线程等待,让获取对象的线程去打印属性
/** * Created by liwei on 16/7/18. * 既保证了数据安全,也保证了数据好看 */public class SetThread implements Runnable { private Student student; private Integer x= 0; public SetThread(Student student){ this.student = student; } @Override public void run() { while (true){ synchronized (student){ if(student.flag){ try { // 这个时候,这个线程释放了锁 student.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if(x%2==0){ student.name = "liwei"; student.age = 29; }else { student.name="zhouguang"; student.age = 26; } x++; // 修改标记 student.flag =true; // 唤醒其它线程 // // TODO: 16/7/18 和 notifyAll 有什么不同 student.notify(); } } }}
(2)打印对象属性的线程:如果这个线程对象的旗标显示这个设置的对象还没被打印过,就打印,如果打印过了,这个线程就挂起,等待对象属性被重新赋值。
/** * Created by liwei on 16/7/18. * 既保证了数据安全,也保证了数据好看 */public class GetThread implements Runnable { private Student student; public GetThread(Student student){ this.student = student; } @Override public void run() { while (true){ synchronized (student){ // 如果还没有被赋值 if(!student.flag){ try { // 当前线程就被挂起,直到满足竞争条件以后再往下执行 // 这个时候,该线程处于等待状态,释放了锁。 // 等到将来醒过来的时候,就继续执行后面的代码 student.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("数据 => " + student.name + " --- " + student.age); // 已经打印过了,就将标记设置为 false student.flag = false; // 此时,我做完了所有的事情,就通知其它线程,可以继续了 // 唤醒线程 student.notify(); } } }}
3、测试代码
/** * Created by liwei on 16/7/18. * * 以上的代码保障了数据的正确,但是不保证数据好看。 * 如果要数据好看,就要引入等待、唤醒机制。 * 要点:添加了一个标记 * 测试流程: 数据错落有致。 * *//* * 分析: * 资源类:Student * 设置学生数据:SetThread(生产者) * 获取学生数据:GetThread(消费者) * 测试类:StudentDemo * * 问题1:按照思路写代码,发现数据每次都是:null---0 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个 * 如何实现呢? * 在外界把这个数据创建出来,通过构造方法传递给其他的类。 * * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题 * A:同一个数据出现多次 * B:姓名和年龄不匹配 * 原因: * A:同一个数据出现多次 * CPU的一点点时间片的执行权,就足够你执行很多次。 * B:姓名和年龄不匹配 * 线程运行的随机性 * 线程安全问题: * A:是否是多线程环境 是 * B:是否有共享数据 是 * C:是否有多条语句操作共享数据 是 * 解决方案: * 加锁。 * 注意: * A:不同种类的线程都要加锁。 * B:不同种类的线程加的锁必须是同一把。 * * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。 * 如何实现呢? * 通过Java提供的等待唤醒机制解决。 * * 等待唤醒: * Object类中提供了三个方法: * wait():等待 * notify():唤醒单个线程 * notifyAll():唤醒所有线程 * 为什么这些方法不定义在Thread类中呢? * 这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。 * 所以,这些方法必须定义在Object类中。 */public class StudentDemo { public static void main(String[] args) { Student student = new Student(); GetThread gt = new GetThread(student); SetThread st = new SetThread(student); Thread t1 = new Thread(gt); Thread t2 = new Thread(st); t1.start(); t2.start(); }}
0 0
- 多线程 —— 代码安全以后,对线程调度的控制(等待-唤醒机制)
- JAVA-15-多线程的调度和控制、线程安全、死锁、等待和唤醒
- JavaSE 多线程 线程间通讯—等待唤醒机制代码优化(背下来)
- JavaSE 多线程 线程间通信— 等待唤醒机制
- 线程的等待唤醒机制(生产者消费者代码)
- 多线程——等待-唤醒机制
- 多线程——等待-唤醒机制的优化
- 多线程的等待唤醒机制
- 线程的等待唤醒机制
- java多线程——线程间通信之线程等待唤醒机制
- 多线程-等待唤醒机制-代码优化
- 线程间通讯------等待唤醒机制(代码优化)
- 多线程等待唤醒机制
- 多线程-等待唤醒机制
- 线程等待唤醒机制
- 24-多线程(线程间通信-等待唤醒机制)1 2图解 3 25-多线程(线程间通信-等待唤醒机制-代码优化)
- 线程间的等待唤醒机制-(一)
- 线程间的通信------------等待唤醒机制
- IT男们,先别慌着coding了,看看了中国又发生了什么吧
- 理解js中的闭包
- 认清经济大形势,别让我们辛苦code来的财富一再缩水
- [原创]通过SSH登录Linux服务器很慢,且服务器提示Access Denied时的解决方案
- C++多态性机制初探
- 多线程 —— 代码安全以后,对线程调度的控制(等待-唤醒机制)
- (一)洞悉linux下的Netfilter&iptables:什么是Netfilter?
- (二)洞悉linux下的Netfilter&iptables:内核中的ip_tables小觑
- (三)洞悉linux下的Netfilter&iptables:内核中的rule,match和target
- (四)洞悉linux下的Netfilter&iptables:包过滤子系统iptable_filter
- (五)洞悉linux下的Netfilter&iptables:如何理解连接跟踪机制?【上】
- (六)洞悉linux下的Netfilter&iptables:如何理解连接跟踪机制?【中】
- JS 基础
- (七)洞悉linux下的Netfilter&iptables:如何理解连接跟踪机制?【下】