针对同一个资源的操作有不同种类的线程:生产线程和消费线程
package com.test; public class Student { String name; int age; }
package com.test; public class SetThread implements Runnable { private Student s; public SetThread(Student s){ this.s = s; } @Override public void run() { s.name="叶胖子"; s.age=27; } }
package com.test; public class GetThread implements Runnable { private Student s; public GetThread(Student s){ this.s = s; } @Override public void run() { System.out.println(s.name+"---"+s.age); } }
package com.test; public class StudentTest { public static void main(String[] args) { Student s = new Student(); SetThread st = new SetThread(s); GetThread gt = new GetThread(s); Thread t1 = new Thread(st); Thread t2 = new Thread(gt); t1.start(); t2.start(); } }
执行结果:
null---0
分析:
资源类:Student
设置学生数据:SetThread(生产者)
获取学生数据:GetThread(消费者)
测试类:StudentTest
问题一:执行测试类,发现输出结果是null---0
原因:我们在每个线程中都创建了新的资源,而我们要求的是设置和获取的资源应该是同一个学生对象。
解决办法:在外界把这个对象创建出来,通过构造方法传递给生产者和消费者。
问题二:为了数据的效果好一些,我如果加入了循环和判断,给出不同的值,这时会出现新的问题
A:同一个数据出现多次
B:姓名和年龄不匹配
原因:A:同一个数据出现多次,CPU的一点点时间片的执行权,就足够你执行很多次。
B:姓名和年龄不匹配,是因为线程运行的随机性。
线程安全问题:
A:是否是多线程环境(是)
B:是否有共享数据(是)
C:是否有多条语句操作共享数据(是)
解决方案:加锁
注意:A:不同种类的线程都要加锁
B:不同种类的线程加的锁必须是同一把
实现线程安全后的代码如下:
package com.test; public class Student { String name; int age; }
package com.test; public class SetThread implements Runnable { private Student s; private int x = 0; public SetThread(Student s){ this.s = s; } @Override public void run() { while(true){ synchronized (s){ if(x%2==0){ s.name="叶胖子"; s.age=30; }else{ s.name="王瘦子"; s.age=31; } x++; } } } }
package com.test; public class GetThread implements Runnable { private Student s; public GetThread(Student s){ this.s = s; } @Override public void run() { while (true){ synchronized(s){ System.out.println(s.name+"---"+s.age); } } } }
package com.test; public class StudentTest { public static void main(String[] args) { Student s = new Student(); SetThread st = new SetThread(s); GetThread gt = new GetThread(s); Thread t1 = new Thread(st); Thread t2 = new Thread(gt); t1.start(); t2.start(); } }