一句话总结:
通过wait 、notify、synchronized锁、flag标记位来实现线程的交替执行
核心代码:
synchronized (s) { if (s.flag) s.wait(); //自定义操作 s.flag = true; s.notify(); }
-------------------------------------------------------对上课内容的总结如下-------------------------------------------------------
代码目的:实现女孩线程和男孩线程交替问问题
一、两个线程仅加锁的情况,会出现一个线程重复抢占资源
package cn.sgy.io.system; public class WaitNotifyDemo { public static void main(String[] args) { Student s = new Student(); s.setName("Tom"); s.setGender('男'); new Thread(new Ask(s)).start(); new Thread(new Change(s)).start(); } } class Change implements Runnable { private Student s; public Change(Student s) { this.s = s; } public void run() { while (true) { synchronized (s){if (s.getGender() == '男') { s.setName("Amy"); s.setGender('女'); } else { s.setName("Tom"); s.setGender('男'); } } } } } class Ask implements Runnable { private Student s; public Ask(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { System.out.println("我是" + s.getName() + ",我是" + s.getGender()); System.out.println("请教了一个问题~~~"); } } } } class Student { private String name; private char gender; public String getName() { return name; } public void setName(String name) { this.name = name; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } }
二、两个线程加锁内加Thread.sleep,结果无济于事只会让程序变慢(sleep不会打破锁机制)
package cn.sgy.io.system; public class WaitNotifyDemo { public static void main(String[] args) { Student s = new Student(); s.setName("Tom"); s.setGender('男'); new Thread(new Ask(s)).start(); new Thread(new Change(s)).start(); } } class Change implements Runnable { private Student s; public Change(Student s) { this.s = s; } public void run() { while (true) { synchronized (s) { if (s.getGender() == '男') { s.setName("Amy"); s.setGender('女'); } else { s.setName("Tom"); s.setGender('男'); } try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } class Ask implements Runnable { private Student s; public Ask(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { System.out.println("我是" + s.getName() + ",我是" + s.getGender()); System.out.println("请教了一个问题~~~"); } try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class Student { private String name; private char gender; public String getName() { return name; } public void setName(String name) { this.name = name; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } }
三、在锁内加入等待唤醒机制,结果两个线程都在等待没有任何输出
package cn.sgy.io.system; public class WaitNotifyDemo { public static void main(String[] args) { Student s = new Student(); s.setName("Tom"); s.setGender('男'); new Thread(new Ask(s)).start(); new Thread(new Change(s)).start(); } } class Change implements Runnable { private Student s; public Change(Student s) { this.s = s; } public void run() { while (true) { synchronized (s) { try { s.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }if (s.getGender() == '男') { s.setName("Amy"); s.setGender('女'); } else { s.setName("Tom"); s.setGender('男'); } s.notify(); } } } } class Ask implements Runnable { private Student s; public Ask(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { try { s.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("我是" + s.getName() + ",我是" + s.getGender()); System.out.println("请教了一个问题~~~"); } s.notify(); } } } class Student { private String name; private char gender; public String getName() { return name; } public void setName(String name) { this.name = name; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } }
四、加入标记位(flag=true -> Ask线程 flag=false -> Change线程)
package cn.sgy.io.system; public class WaitNotifyDemo { public static void main(String[] args) { Student s = new Student(); s.setName("Tom"); s.setGender('男'); new Thread(new Ask(s)).start(); new Thread(new Change(s)).start(); } } class Change implements Runnable { private Student s; public Change(Student s) { this.s = s; } public void run() { while (true) { synchronized (s) { if(s.flag == true) try { s.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (s.getGender() == '男') { s.setName("Amy"); s.setGender('女'); } else { s.setName("Tom"); s.setGender('男'); } s.flag=true; s.notify(); } } } } class Ask implements Runnable { private Student s; public Ask(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { if(s.flag == false)try { s.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("我是" + s.getName() + ",我是" + s.getGender()); System.out.println("请教了一个问题~~~"); s.flag = false; s.notify(); } } } } class Student { private String name; private char gender; public boolean flag = true; public String getName() { return name; } public void setName(String name) { this.name = name; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } }
五、每个线程类对应了两个线程后出现问题
package cn.tedu.thread; public class WaitNotifyAllDemo { public static void main(String[] args) { Student s = new Student(); s.setName("Tom"); s.setGender('男'); new Thread(new Ask2(s)).start(); new Thread(new Ask2(s)).start(); new Thread(new Change2(s)).start(); new Thread(new Change2(s)).start(); } } class Change2 implements Runnable { private Student s; public Change2(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { while (s.flag) try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } if (s.getGender() == '男') { s.setName("Amy"); s.setGender('女'); } else { s.setName("Tom"); s.setGender('男'); } s.flag = true; // 唤醒在等待的线程 s.notify(); } } } } class Ask2 implements Runnable { private Student s; public Ask2(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { while (!s.flag) try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我是" + s.getName() + ",我是" + s.getGender()); System.out.println("请教了一个问题~~~"); s.flag = false; s.notify(); } } } }
六、出现问题的原因
知识基础:线程在等待期间是在这个锁所对应的线程池(队列)中等待
一句话总结:A执行完,应该释放C时却把排在C前面的A释放,导致C无法执行
解释:A1为 Ask线程 A2为Ask2线程 两者为同一操作
C1为Change线程 C2位Change2线程 两者为同一操作
因为队列只能先进先出,所以释放的时候都是释放最先进入的元素,所以当遇到且仅遇到以下两种情况时会出现全部进入线程池的情况
当C程序执行结束,而C线程再一次抢到资源的时候,因为交替执行需要的A线程,所以把抢到资源的C1和C2都放入了线程池中,这时才轮到A2线程来执行A程序
七、使用 s.notifyAll()解决问题
notifyAll用于释放线程池中的所有等待的线程,因为使得代码整洁才使用这种低效率的方法
package cn.tedu.thread; public class WaitNotifyAllDemo { public static void main(String[] args) { Student s = new Student(); s.setName("Tom"); s.setGender('男'); new Thread(new Ask2(s)).start(); new Thread(new Ask2(s)).start(); new Thread(new Change2(s)).start(); new Thread(new Change2(s)).start(); } } class Change2 implements Runnable { private Student s; public Change2(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { while (s.flag) try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } if (s.getGender() == '男') { s.setName("Amy"); s.setGender('女'); } else { s.setName("Tom"); s.setGender('男'); } s.flag = true; // 唤醒在等待的线程 s.notifyAll(); } } } } class Ask2 implements Runnable { private Student s; public Ask2(Student s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { while (!s.flag) try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我是" + s.getName() + ",我是" + s.getGender()); System.out.println("请教了一个问题~~~"); s.flag = false; s.notifyAll(); } } } }
-------------------------------------------------------谢谢观看,如有问题还请指正-------------------------------------------------------