同步解决线程安全问题的三种实现
/*
* 同步可以解决安全问题的根本原因就在那个对象上。
*
* A:同步代码块的格式及其锁对象问题?
* 格式:
* synchronized (对象名称) {
* 需要同步的代码;
* }
*
* 同步代码块的锁对象是谁呢?
* 任意对象。
*
* B:同步方法的格式及其锁对象问题?
* 如果一个方法一进去就看到了代码被同步了,那么我就在想能不能把这个同步加在方法上呢? 答:能。
* 把同步关键字加在方法上。
* 格式:
* synchronized private void sellTicket() {...}
* private synchronized void sellTicket() {...} // 习惯上这样写
*
* 同步方法的锁对象是谁呢?(方法的内部有一个你看不到的对象是this啊,傻瓜哈)
* this
*
* C:静态同步方法的格式及其锁对象问题?
* 格式:
* private static synchronized void sellTicket() {...}
*
* 静态同步方法的锁对象是谁呢?
* 当前类的字节码文件对象。(反射会讲)
*
* 类的初始化过程:Person p = new Person(); // 第一步做的事情是:把Person.class文件加载进内存。在Person.class文件中找到main方法并放到栈。
* 因为静态是随着类的加载而加载。此时对象this根本就不存在。此时的对象是.class文件(字节码文件)。
*
* 简言之:要想同步,需要先确定同步的对象。
* 要在静态同步方法加载之前就得先确定同步的对象,(否则你跟我咋同步)
* 谁比静态先存在呢? 答:只有.class文件(字节码文件)
*
*/
那么,我们到底使用谁?
如果锁对象是this,就可以考虑使用同步方法。
否则能使用同步代码块的尽量使用同步代码块。
示例代码如下:

1 package cn.itcast_11; 2 3 /* 4 * 同步可以解决安全问题的根本原因就在那个对象上。 5 * 6 * A:同步代码块的格式及其锁对象是谁呢? 7 * 格式: 8 * synchronized (对象名称) { 9 * 需要同步的代码; 10 * } 11 * 12 * 同步代码块的锁对象是谁呢? 13 * 任意对象。 14 * 15 * B:同步方法的格式及其锁对象问题? 16 * 如果一个方法一进去就看到了代码被同步了,那么我就在想能不能把这个同步加在方法上呢? 答:能。 17 * 把同步关键字加在方法上。 18 * 格式: 19 * synchronized private void sellTicket() {...} 20 * private synchronized void sellTicket() {...} // 习惯上这样写 21 * 22 * 同步方法的锁对象是谁呢?(方法的内部有一个你看不到的对象是this啊,傻瓜哈) 23 * this 24 * 25 * C:静态同步方法的格式及其锁对象问题? 26 * 格式: 27 * private static synchronized void sellTicket() {...} 28 * 29 * 静态同步方法的锁对象是谁呢? 30 * 当前类的字节码文件对象。(反射会讲) 31 * 32 * 类的初始化过程:Person p = new Person(); // 第一步做的事情是:把Person.class文件加载进内存。在Person.class文件中找到main方法并放到栈。 33 * 因为静态是随着类的加载而加载。此时对象this根本就不存在。此时的对象是.class文件(字节码文件)。 34 * 35 * 简言之:要想同步,需要先确定同步的对象。 36 * 要在静态同步方法加载之前就得先确定同步的对象,(否则你跟我咋同步) 37 * 谁比静态先存在呢? 答:只有.class文件(字节码文件) 38 * 39 */ 40 public class SellTicketDemo { 41 public static void main(String[] args) { 42 // 创建资源对象 43 SellTicket st = new SellTicket(); 44 45 // 创建三个线程对象 46 Thread t1 = new Thread(st, "窗口1"); 47 Thread t2 = new Thread(st, "窗口2"); 48 Thread t3 = new Thread(st, "窗口3"); 49 50 // 启动线程 51 t1.start(); 52 t2.start(); 53 t3.start(); 54 } 55 }

1 package cn.itcast_11; 2 3 public class SellTicket implements Runnable { 4 5 // 定义100张票 6 private static int tickets = 100; 7 8 // 定义同一把锁为obj对象 9 private Object obj = new Object(); 10 11 // 定义同一把锁为任意对象 12 private Demo d = new Demo(); 13 14 private int x = 0; 15 16 /* 17 // 同步代码块用obj对象做锁 18 @Override 19 public void run() { 20 while (true) { 21 synchronized (obj) { 22 if (tickets > 0) { 23 try { 24 Thread.sleep(100); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); 29 } 30 } 31 } 32 } 33 */ 34 35 /* 36 // 同步代码块用任意对象做锁 37 @Override 38 public void run() { 39 while (true) { 40 synchronized (d) { 41 if (tickets > 0) { 42 try { 43 Thread.sleep(100); 44 } catch (InterruptedException e) { 45 e.printStackTrace(); 46 } 47 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); 48 } 49 } 50 } 51 } 52 */ 53 54 @Override 55 public void run() { 56 while (true) { 57 if (x % 2 == 0) { 58 synchronized (SellTicket.class) { 59 if (tickets > 0) { 60 try { 61 Thread.sleep(100); 62 } catch (InterruptedException e) { 63 e.printStackTrace(); 64 } 65 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); 66 } 67 } 68 } else { 69 /* 70 synchronized (d) { 71 if (tickets > 0) { 72 try { 73 Thread.sleep(100); 74 } catch (InterruptedException e) { 75 e.printStackTrace(); 76 } 77 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); 78 } 79 } 80 */ 81 sellTicket(); 82 } 83 x++; 84 } 85 } 86 87 88 /* 89 private void sellTicket() { 90 synchronized (d) { 91 if (tickets > 0) { 92 try { 93 Thread.sleep(100); 94 } catch (InterruptedException e) { 95 e.printStackTrace(); 96 } 97 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); 98 } 99 } 100 } 101 */ 102 103 /* 104 // 如果一个方法一进去就看到了代码被同步了,那么我就在想能不能把这个同步加在方法上呢? 答:能。 105 // 同步方法 106 private synchronized void sellTicket() { 107 if (tickets > 0) { 108 try { 109 Thread.sleep(100); 110 } catch (InterruptedException e) { 111 e.printStackTrace(); 112 } 113 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); 114 } 115 } 116 */ 117 118 // 静态同步方法 119 private static synchronized void sellTicket() { 120 if (tickets > 0) { 121 try { 122 Thread.sleep(100); 123 } catch (InterruptedException e) { 124 e.printStackTrace(); 125 } 126 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); 127 } 128 } 129 130 } 131 132 class Demo { 133 }