同步解决线程安全问题的三种实现

简介: 同步解决线程安全问题的三种实现 /* * 同步可以解决安全问题的根本原因就在那个对象上。 * * A:同步代码块的格式及其锁对象问题? * 格式: * synchronized (对象名称) { * 需要同步的代码; * } * * 同步代码块的锁对象是谁呢? * 任意对象。

同步解决线程安全问题的三种实现

/*
 * 同步可以解决安全问题的根本原因就在那个对象上。
 * 
 * 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 }
SellTicketDemo.java
  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 }
SellTicket.java

 

我的GitHub地址: https://github.com/heizemingjun
我的博客园地址: http://www.cnblogs.com/chenmingjun
我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun
Copyright ©2018 黑泽明军
【转载文章务必保留出处和署名,谢谢!】
相关文章
|
2月前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
Java多线程同步大揭秘:synchronized与Lock的终极对决!
59 5
|
4月前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
【6月更文挑战第20天】在Java多线程编程中,`synchronized`和`Lock`是两种关键的同步机制。`synchronized`作为内置关键字提供基础同步,简单但可能不够灵活;而`Lock`接口自Java 5引入,提供更复杂的控制和优化性能的选项。在低竞争场景下,`synchronized`性能可能更好,但在高并发或需要精细控制时,`Lock`(如`ReentrantLock`)更具优势。选择哪种取决于具体需求和场景,理解两者机制至关重要。
41 1
|
4月前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
【6月更文挑战第20天】Java多线程同步始于`synchronized`关键字,保证单线程访问共享资源,但为应对复杂场景,`Lock`接口(如`ReentrantLock`)提供了更细粒度控制,包括可重入、公平性及中断等待。通过实战比较两者在高并发下的性能,了解其应用场景。不断学习如`Semaphore`等工具并实践,能提升多线程编程能力。从同步起点到专家之路,每次实战都是进步的阶梯。
46 0
|
4月前
|
Java 程序员
从0到1,手把手教你玩转Java多线程同步!
【6月更文挑战第20天】从0到1学Java多线程同步:理解线程同步关键,掌握`synchronized`用法,探索`Lock`接口,实战演练并进阶学习锁升级、`Condition`及死锁预防,成为多线程大师!
24 0
|
2月前
|
安全 Java 开发者
Java多线程同步:synchronized与Lock的“爱恨情仇”!
Java多线程同步:synchronized与Lock的“爱恨情仇”!
81 5
|
2月前
|
Java 程序员
从0到1,手把手教你玩转Java多线程同步!
从0到1,手把手教你玩转Java多线程同步!
23 3
|
2月前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
Java多线程同步实战:从synchronized到Lock的进化之路!
86 1
|
2月前
|
存储 Java 开发者
HashMap线程安全问题大揭秘:ConcurrentHashMap、自定义同步,一文让你彻底解锁!
【8月更文挑战第24天】HashMap是Java集合框架中不可或缺的一部分,以其高效的键值对存储和快速访问能力广受开发者欢迎。本文深入探讨了HashMap在JDK 1.8后的底层结构——数组+链表+红黑树混合模式,这种设计既利用了数组的快速定位优势,又通过链表和红黑树有效解决了哈希冲突问题。数组作为基石,每个元素包含一个Node节点,通过next指针形成链表;当链表长度过长时,采用红黑树进行优化,显著提升性能。此外,还介绍了HashMap的扩容机制,确保即使在数据量增大时也能保持高效运作。通过示例代码展示如何使用HashMap进行基本操作,帮助理解其实现原理及应用场景。
34 1
|
2月前
|
Java 调度 开发者
Java并发编程:解锁多线程同步的奥秘
在Java的世界里,并发编程是提升应用性能的关键所在。本文将深入浅出地探讨Java中的并发工具和同步机制,带领读者从基础到进阶,逐步掌握多线程编程的核心技巧。通过实例演示,我们将一起探索如何在多线程环境下保持数据的一致性,以及如何有效利用线程池来管理资源。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你对Java并发编程有更深入的理解和应用。
|
3月前
|
安全 Java 程序员
Java 并发编程:解锁多线程同步的奥秘
【7月更文挑战第30天】在Java的世界里,并发编程是一块充满挑战的领域。它如同一位严苛的导师,要求我们深入理解其运作机制,才能驾驭多线程的力量。本文将带你探索Java并发编程的核心概念,包括线程同步与通信、锁机制、以及并发集合的使用。我们将通过实例代码,揭示如何在多线程环境中保持数据的一致性和完整性,确保你的应用程序既高效又稳定。准备好了吗?让我们一同踏上这段解锁Java并发之谜的旅程。
36 5