1. 同步弊端:
(1)效率低
(2)如果出现了同步嵌套,就容易产生死锁问题
死锁问题及其代码 :
(1)是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
(2)同步代码块的嵌套案例
1 package cn.itcast_02; 2 3 public class MyLock { 4 // 创建两把锁对象 5 public static final Object objA = new Object(); 6 public static final Object objB = new Object(); 7 }
1 package cn.itcast_02; 2 3 public class DieLock extends Thread { 4 5 private boolean flag; 6 7 public DieLock(boolean flag) { 8 this.flag = flag; 9 } 10 11 @Override 12 public void run() { 13 if (flag) { 14 synchronized (MyLock.objA) { 15 System.out.println("if objA"); 16 synchronized (MyLock.objB) { 17 System.out.println("if objB"); 18 } 19 } 20 } else { 21 synchronized (MyLock.objB) { 22 System.out.println("else objB"); 23 synchronized (MyLock.objA) { 24 System.out.println("else objA"); 25 } 26 } 27 } 28 } 29 }
1 package cn.itcast_02; 2 3 /* 4 * 同步的弊端: 5 * A:效率低 6 * B:容易产生死锁 7 * 8 * 死锁: 9 * 两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。 10 * 11 * 举例: 12 * 中国人,美国人吃饭案例。 13 * 正常情况: 14 * 中国人:筷子两支 15 * 美国人:刀和叉 16 * 现在: 17 * 中国人:筷子1支,刀一把 18 * 美国人:筷子1支,叉一把 19 */ 20 public class DieLockDemo { 21 public static void main(String[] args) { 22 DieLock dl1 = new DieLock(true); 23 DieLock dl2 = new DieLock(false); 24 25 dl1.start(); 26 dl2.start(); 27 } 28 }
我们执行的时候会发现程序会锁住(当然这个只是很大几率会锁住):如下图
这里死锁我们该怎么解决呢?这里引出了线程之间通信:
不同种类的线程针对同一个资源的操作
2. 下面设置线程(生产者)和获取线程(消费者)针对同一个学生对象进行操作示例:
代码实现:
1 package cn.itcast_03; 2 3 /* 4 * 分析: 5 * 资源类:Student 6 * 设置学生数据:SetThread(生产者) 7 * 获取学生数据:GetThread(消费者) 8 * 测试类:StudentDemo 9 * 10 * 问题1:按照思路写代码,发现数据每次都是:null---0 11 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个 12 * 如何实现呢?这里是共享资源一种思路 13 * 在外界把这个数据创建出来,通过构造方法传递给其他的类。 14 * 15 */ 16 public class StudentDemo { 17 public static void main(String[] args) { 18 //创建资源----外界创建出资源 19 Student s = new Student(); 20 21 //设置和获取的类(这两个线程类被刚刚创建的资源绑定) 22 SetThread st = new SetThread(s);//通过构造方法传递给其他类 23 GetThread gt = new GetThread(s);//通过构造方法传递给其他类 24 25 //线程类 26 Thread t1 = new Thread(st); 27 Thread t2 = new Thread(gt); 28 29 //启动线程 30 t1.start(); 31 t2.start(); 32 } 33 }
1 package cn.itcast_03; 2 3 public class SetThread implements Runnable { 4 5 private Student s; 6 7 public SetThread(Student s) { 8 this.s = s; 9 } 10 11 @Override 12 public void run() { 13 // Student s = new Student(); 14 s.name = "林青霞"; 15 s.age = 27; 16 } 17 18 }
1 package cn.itcast_03; 2 3 public class GetThread implements Runnable { 4 private Student s; 5 6 public GetThread(Student s) { 7 this.s = s; 8 } 9 10 @Override 11 public void run() { 12 // Student s = new Student();//上面SetThread()类中run()方法也出现Student s = new Student(),这样就出现两个不同的对象 13 System.out.println(s.name + "---" + s.age); 14 } 15 16 }
1 package cn.itcast_03; 2 3 public class Student { 4 String name; 5 int age; 6 }
上面代码是有问题的,如下:
进一步改进上面代码:
1 package cn.itcast_04; 2 3 /* 4 * 分析: 5 * 资源类:Student 6 * 设置学生数据:SetThread(生产者) 7 * 获取学生数据:GetThread(消费者) 8 * 测试类:StudentDemo 9 * 10 * 问题1:按照思路写代码,发现数据每次都是:null---0 11 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个 12 * 如何实现呢? 13 * 在外界把这个数据创建出来,通过构造方法传递给其他的类。 14 * 15 * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题 16 * A:同一个数据出现多次 17 * B:姓名和年龄不匹配 18 * 原因: 19 * A:同一个数据出现多次 20 * CPU的一点点时间片的执行权,就足够你执行很多次。 21 * B:姓名和年龄不匹配 22 * 线程运行的随机性 23 * 线程安全问题: 24 * A:是否是多线程环境 是 25 * B:是否有共享数据 是 26 * C:是否有多条语句操作共享数据 是 27 * 解决方案: 28 * 加锁。 29 * 注意: 30 * A:不同种类的线程都要加锁。 31 * B:不同种类的线程加的锁必须是同一把。 32 */ 33 public class StudentDemo { 34 public static void main(String[] args) { 35 //创建资源 36 Student s = new Student(); 37 38 //设置和获取的类 39 SetThread st = new SetThread(s); 40 GetThread gt = new GetThread(s); 41 42 //线程类 43 Thread t1 = new Thread(st); 44 Thread t2 = new Thread(gt); 45 46 //启动线程 47 t1.start(); 48 t2.start(); 49 } 50 }
1 package cn.itcast_04; 2 3 public class SetThread implements Runnable { 4 5 private Student s; 6 private int x = 0; 7 8 public SetThread(Student s) { 9 this.s = s; 10 } 11 12 @Override 13 public void run() { 14 while (true) { 15 synchronized (s) { 16 if (x % 2 == 0) { 17 s.name = "林青霞";//刚走到这里,就被别人抢到了执行权 18 s.age = 27; 19 } else { 20 s.name = "刘意"; //刚走到这里,就被别人抢到了执行权 21 s.age = 30; 22 } 23 x++; 24 } 25 } 26 } 27 }
1 package cn.itcast_04; 2 3 public class GetThread implements Runnable { 4 private Student s; 5 6 public GetThread(Student s) { 7 this.s = s; 8 } 9 10 @Override 11 public void run() { 12 while (true) { 13 synchronized (s) { 14 System.out.println(s.name + "---" + s.age); 15 } 16 } 17 } 18 }
1 package cn.itcast_04; 2 3 public class Student { 4 String name; 5 int age; 6 }