synchronized详解

来源:互联网 发布:端口卷边夹具价格 编辑:程序博客网 时间:2024/06/05 03:59

Java中Synchronized的用法

标签: javasynchroniz线程同步多线程
23811人阅读 评论(14)收藏举报
分类:
作者同类文章X
  • 编程思想之多线程与多进程(4)——C++中的多线程
  • 编程思想之多线程与多进程(2)——线程优先级与线程安全
  • 编程思想之多线程与多进程(3)——Java中的多线程
  • Java多线程中wait, notify and notifyAll的使用
  • 更多

目录(?)[-]

  1. 修饰一个代码块
  2. 修饰一个方法
  3. 修饰一个静态的方法
  4. 修饰一个类
  5. 总结

原文:http://blog.csdn.net/luoweifu/article/details/46613015
作者:luoweifu
转载请标名出处


《编程思想之多线程与多进程(1)——以操作系统的角度述说线程与进程》一文详细讲述了线程、进程的关系及在操作系统中的表现,这是多线程学习必须了解的基础。本文将接着讲一下Java线程同步中的一个重要的概念synchronized.

synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。


修饰一个代码块

  1. 一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞。我们看下面一个例子:

【Demo1】:synchronized的用法

<code class="language-java hljs  has-numbering"><span class="hljs-javadoc">/** * 同步线程 */</span>class SyncThread implements Runnable {   <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> count;   <span class="hljs-keyword">public</span> <span class="hljs-title">SyncThread</span>() {      count = <span class="hljs-number">0</span>;   }   <span class="hljs-keyword">public</span>  <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {      <span class="hljs-keyword">synchronized</span>(<span class="hljs-keyword">this</span>) {         <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++) {            <span class="hljs-keyword">try</span> {               System.out.println(Thread.currentThread().getName() + <span class="hljs-string">":"</span> + (count++));               Thread.sleep(<span class="hljs-number">100</span>);            } <span class="hljs-keyword">catch</span> (InterruptedException e) {               e.printStackTrace();            }         }      }   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCount</span>() {      <span class="hljs-keyword">return</span> count;   }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li></ul>

SyncThread的调用:

<code class="hljs lasso has-numbering">SyncThread syncThread <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> SyncThread();<span class="hljs-keyword">Thread</span> thread1 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> <span class="hljs-keyword">Thread</span>(syncThread, <span class="hljs-string">"SyncThread1"</span>);<span class="hljs-keyword">Thread</span> thread2 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> <span class="hljs-keyword">Thread</span>(syncThread, <span class="hljs-string">"SyncThread2"</span>);thread1<span class="hljs-built_in">.</span>start();thread2<span class="hljs-built_in">.</span>start();</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>

结果如下:

SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9*

当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。
我们再把SyncThread的调用稍微改一下:

<code class="hljs lasso has-numbering"><span class="hljs-keyword">Thread</span> thread1 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> <span class="hljs-keyword">Thread</span>(<span class="hljs-literal">new</span> SyncThread(), <span class="hljs-string">"SyncThread1"</span>);<span class="hljs-keyword">Thread</span> thread2 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> <span class="hljs-keyword">Thread</span>(<span class="hljs-literal">new</span> SyncThread(), <span class="hljs-string">"SyncThread2"</span>);thread1<span class="hljs-built_in">.</span>start();thread2<span class="hljs-built_in">.</span>start();</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

结果如下:

SyncThread1:0
SyncThread2:1
SyncThread1:2
SyncThread2:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread1:7
SyncThread1:8
SyncThread2:9

不是说一个线程执行synchronized代码块时其它的线程受阻塞吗?为什么上面的例子中thread1和thread2同时在执行。这是因为synchronized只锁定对象,每个对象只有一个锁(lock)与之相关联,而上面的代码等同于下面这段代码:

<code class="language-java hljs  has-numbering">SyncThread syncThread1 = <span class="hljs-keyword">new</span> SyncThread();SyncThread syncThread2 = <span class="hljs-keyword">new</span> SyncThread();Thread thread1 = <span class="hljs-keyword">new</span> Thread(syncThread1, <span class="hljs-string">"SyncThread1"</span>);Thread thread2 = <span class="hljs-keyword">new</span> Thread(syncThread2, <span class="hljs-string">"SyncThread2"</span>);thread1.start();thread2.start();</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

这时创建了两个SyncThread的对象syncThread1和syncThread2,线程thread1执行的是syncThread1对象中的synchronized代码(run),而线程thread2执行的是syncThread2对象中的synchronized代码(run);我们知道synchronized锁定的是对象,这时会有两把锁分别锁定syncThread1对象和syncThread2对象,而这两把锁是互不干扰的,不形成互斥,所以两个线程可以同时执行。


2.当一个线程访问对象的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。
【Demo2】:多个线程访问synchronized和非synchronized代码块

<code class="hljs axapta has-numbering"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span> <span class="hljs-inheritance"><span class="hljs-keyword">implements</span></span> <span class="hljs-title">Runnable</span>{</span>   <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> <span class="hljs-keyword">count</span>;   <span class="hljs-keyword">public</span> Counter() {      <span class="hljs-keyword">count</span> = <span class="hljs-number">0</span>;   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> countAdd() {      synchronized(<span class="hljs-keyword">this</span>) {         <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i ++) {            <span class="hljs-keyword">try</span> {               System.out.println(Thread.currentThread().getName() + <span class="hljs-string">":"</span> + (<span class="hljs-keyword">count</span>++));               Thread.sleep(<span class="hljs-number">100</span>);            } <span class="hljs-keyword">catch</span> (InterruptedException e) {               e.printStackTrace();            }         }      }   }   <span class="hljs-comment">//非synchronized代码块,未对count进行读写操作,所以可以不用synchronized</span>   <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> printCount() {      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i ++) {         <span class="hljs-keyword">try</span> {            System.out.println(Thread.currentThread().getName() + <span class="hljs-string">" count:"</span> + <span class="hljs-keyword">count</span>);            Thread.sleep(<span class="hljs-number">100</span>);         } <span class="hljs-keyword">catch</span> (InterruptedException e) {            e.printStackTrace();         }      }   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> run() {      String threadName = Thread.currentThread().getName();      <span class="hljs-keyword">if</span> (threadName.equals(<span class="hljs-string">"A"</span>)) {         countAdd();      } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (threadName.equals(<span class="hljs-string">"B"</span>)) {         printCount();      }   }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li></ul>

调用代码:

<code class="hljs lasso has-numbering">Counter counter <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> Counter();<span class="hljs-keyword">Thread</span> thread1 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> <span class="hljs-keyword">Thread</span>(counter, <span class="hljs-string">"A"</span>);<span class="hljs-keyword">Thread</span> thread2 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> <span class="hljs-keyword">Thread</span>(counter, <span class="hljs-string">"B"</span>);thread1<span class="hljs-built_in">.</span>start();thread2<span class="hljs-built_in">.</span>start();</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>

结果如下:

A:0
B count:1
A:1
B count:2
A:2
B count:3
A:3
B count:4
A:4
B count:5

上面代码中countAdd是一个synchronized的,printCount是非synchronized的。从上面的结果中可以看出一个线程访问一个对象的synchronized代码块时,别的线程可以访问该对象的非synchronized代码块而不受阻塞。


  1. 指定要给某个对象加锁

【Demo3】:指定要给某个对象加锁

<code class="hljs java has-numbering"><span class="hljs-javadoc">/** * 银行账户类 */</span>class Account {   String name;   <span class="hljs-keyword">float</span> amount;   <span class="hljs-keyword">public</span> <span class="hljs-title">Account</span>(String name, <span class="hljs-keyword">float</span> amount) {      <span class="hljs-keyword">this</span>.name = name;      <span class="hljs-keyword">this</span>.amount = amount;   }   <span class="hljs-comment">//存钱</span>   <span class="hljs-keyword">public</span>  <span class="hljs-keyword">void</span> <span class="hljs-title">deposit</span>(<span class="hljs-keyword">float</span> amt) {      amount += amt;      <span class="hljs-keyword">try</span> {         Thread.sleep(<span class="hljs-number">100</span>);      } <span class="hljs-keyword">catch</span> (InterruptedException e) {         e.printStackTrace();      }   }   <span class="hljs-comment">//取钱</span>   <span class="hljs-keyword">public</span>  <span class="hljs-keyword">void</span> <span class="hljs-title">withdraw</span>(<span class="hljs-keyword">float</span> amt) {      amount -= amt;      <span class="hljs-keyword">try</span> {         Thread.sleep(<span class="hljs-number">100</span>);      } <span class="hljs-keyword">catch</span> (InterruptedException e) {         e.printStackTrace();      }   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">float</span> <span class="hljs-title">getBalance</span>() {      <span class="hljs-keyword">return</span> amount;   }}<span class="hljs-javadoc">/** * 账户操作类 */</span>class AccountOperator implements Runnable{   <span class="hljs-keyword">private</span> Account account;   <span class="hljs-keyword">public</span> <span class="hljs-title">AccountOperator</span>(Account account) {      <span class="hljs-keyword">this</span>.account = account;   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {      <span class="hljs-keyword">synchronized</span> (account) {         account.deposit(<span class="hljs-number">500</span>);         account.withdraw(<span class="hljs-number">500</span>);         System.out.println(Thread.currentThread().getName() + <span class="hljs-string">":"</span> + account.getBalance());      }   }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li></ul>

调用代码:

<code class="hljs java has-numbering">Account account = <span class="hljs-keyword">new</span> Account(<span class="hljs-string">"zhang san"</span>, <span class="hljs-number">10000.0</span>f);AccountOperator accountOperator = <span class="hljs-keyword">new</span> AccountOperator(account);<span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> THREAD_NUM = <span class="hljs-number">5</span>;Thread threads[] = <span class="hljs-keyword">new</span> Thread[THREAD_NUM];<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < THREAD_NUM; i ++) {   threads[i] = <span class="hljs-keyword">new</span> Thread(accountOperator, <span class="hljs-string">"Thread"</span> + i);   threads[i].start();}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>

结果如下:

Thread3:10000.0
Thread2:10000.0
Thread1:10000.0
Thread4:10000.0
Thread0:10000.0

在AccountOperator 类中的run方法里,我们用synchronized 给account对象加了锁。这时,当一个线程访问account对象时,其他试图访问account对象的线程将会阻塞,直到该线程访问account对象结束。也就是说谁拿到那个锁谁就可以运行它所控制的那段代码。
当有一个明确的对象作为锁时,就可以用类似下面这样的方式写程序。

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">method3</span>(SomeObject obj){   <span class="hljs-comment">//obj 锁定的对象</span>   <span class="hljs-keyword">synchronized</span>(obj)   {      <span class="hljs-comment">// todo</span>   }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>

当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的对象来充当锁:

<code class="hljs axapta has-numbering"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Test</span> <span class="hljs-inheritance"><span class="hljs-keyword">implements</span></span> <span class="hljs-title">Runnable</span>{</span>   <span class="hljs-keyword">private</span> <span class="hljs-keyword">byte</span>[] lock = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">0</span>];  <span class="hljs-comment">// 特殊的instance变量</span>   <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> method()   {      synchronized(lock) {         <span class="hljs-comment">// todo 同步代码块</span>      }   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> run() {   }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul>

说明:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。

修饰一个方法

Synchronized修饰一个方法很简单,就是在方法的前面加synchronized,public synchronized void method(){//todo}; synchronized修饰方法和修饰一个代码块类似,只是作用范围不一样,修饰代码块是大括号括起来的范围,而修饰方法范围是整个函数。如将【Demo1】中的run方法改成如下的方式,实现的效果一样。

*【Demo4】:synchronized修饰一个方法

<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> synchronized <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {   <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i ++) {      <span class="hljs-keyword">try</span> {         System.<span class="hljs-keyword">out</span>.println(Thread.currentThread().getName() + <span class="hljs-string">":"</span> + (count++));         Thread.sleep(<span class="hljs-number">100</span>);      } <span class="hljs-keyword">catch</span> (InterruptedException e) {         e.printStackTrace();      }   }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

Synchronized作用于整个方法的写法。
写法一:

<code class="hljs oxygene has-numbering"><span class="hljs-keyword">public</span> synchronized void <span class="hljs-function"><span class="hljs-keyword">method</span><span class="hljs-params">()</span><span class="hljs-comment">{   // todo}</span></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

写法二:

<code class="hljs oxygene has-numbering"><span class="hljs-keyword">public</span> void <span class="hljs-function"><span class="hljs-keyword">method</span><span class="hljs-params">()</span><span class="hljs-comment">{   synchronized(this) {      // todo   }</span>}</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

写法一修饰的是一个方法,写法二修饰的是一个代码块,但写法一与写法二是等价的,都是锁定了整个方法时的内容。

在用synchronized修饰方法时要注意以下几点:
1. synchronized关键字不能继承。
虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此,synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。这两种方式的例子代码如下:
在子类方法中加上synchronized关键字

<code class="hljs axapta has-numbering"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Parent</span> {</span>   <span class="hljs-keyword">public</span> synchronized <span class="hljs-keyword">void</span> method() { }}<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Child</span> <span class="hljs-inheritance"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">Parent</span> {</span>   <span class="hljs-keyword">public</span> synchronized <span class="hljs-keyword">void</span> method() { }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

在子类方法中调用父类的同步方法

<code class="hljs axapta has-numbering"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Parent</span> {</span>   <span class="hljs-keyword">public</span> synchronized <span class="hljs-keyword">void</span> method() {   }}<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Child</span> <span class="hljs-inheritance"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">Parent</span> {</span>   <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> method() { <span class="hljs-keyword">super</span>.method();   }} </code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>
  1. 在定义接口方法时不能使用synchronized关键字。
  2. 构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。


修饰一个静态的方法

Synchronized也可修饰一个静态方法,用法如下:

<code class="hljs oxygene has-numbering"><span class="hljs-keyword">public</span> synchronized <span class="hljs-keyword">static</span> void <span class="hljs-function"><span class="hljs-keyword">method</span><span class="hljs-params">()</span> <span class="hljs-comment">{   // todo}</span></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>

我们知道静态方法是属于类的而不属于对象的。同样的,synchronized修饰的静态方法锁定的是这个类的所有对象。我们对Demo1进行一些修改如下:

【Demo5】:synchronized修饰静态方法

<code class="hljs java has-numbering"><span class="hljs-javadoc">/** * 同步线程 */</span>class SyncThread implements Runnable {   <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> count;   <span class="hljs-keyword">public</span> <span class="hljs-title">SyncThread</span>() {      count = <span class="hljs-number">0</span>;   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">method</span>() {      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i ++) {         <span class="hljs-keyword">try</span> {            System.out.println(Thread.currentThread().getName() + <span class="hljs-string">":"</span> + (count++));            Thread.sleep(<span class="hljs-number">100</span>);         } <span class="hljs-keyword">catch</span> (InterruptedException e) {            e.printStackTrace();         }      }   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {      method();   }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li></ul>

调用代码:

<code class="hljs lasso has-numbering">SyncThread syncThread1 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> SyncThread();SyncThread syncThread2 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> SyncThread();<span class="hljs-keyword">Thread</span> thread1 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> <span class="hljs-keyword">Thread</span>(syncThread1, <span class="hljs-string">"SyncThread1"</span>);<span class="hljs-keyword">Thread</span> thread2 <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> <span class="hljs-keyword">Thread</span>(syncThread2, <span class="hljs-string">"SyncThread2"</span>);thread1<span class="hljs-built_in">.</span>start();thread2<span class="hljs-built_in">.</span>start();</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

结果如下:

SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9

syncThread1和syncThread2是SyncThread的两个对象,但在thread1和thread2并发执行时却保持了线程同步。这是因为run中调用了静态方法method,而静态方法是属于类的,所以syncThread1和syncThread2相当于用了同一把锁。这与Demo1是不同的。



修饰一个类

Synchronized还可作用于一个类,用法如下:

<code class="hljs java has-numbering">class ClassName {   <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">method</span>() {      <span class="hljs-keyword">synchronized</span>(ClassName.class) {         <span class="hljs-comment">// todo</span>      }   }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>

我们把Demo5再作一些修改。
【Demo6】:修饰一个类

<code class="hljs java has-numbering"><span class="hljs-javadoc">/** * 同步线程 */</span>class SyncThread implements Runnable {   <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> count;   <span class="hljs-keyword">public</span> <span class="hljs-title">SyncThread</span>() {      count = <span class="hljs-number">0</span>;   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">method</span>() {      <span class="hljs-keyword">synchronized</span>(SyncThread.class) {         <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i ++) {            <span class="hljs-keyword">try</span> {               System.out.println(Thread.currentThread().getName() + <span class="hljs-string">":"</span> + (count++));               Thread.sleep(<span class="hljs-number">100</span>);            } <span class="hljs-keyword">catch</span> (InterruptedException e) {               e.printStackTrace();            }         }      }   }   <span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {      method();   }}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li></ul>

其效果和【Demo5】是一样的,synchronized作用于一个类T时,是给这个类T加锁,T的所有对象用的是同一把锁。



总结:

A. 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
B. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
C. 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。



参考资料:
http://blog.csdn.net/chenguang79/article/details/677720
http://developer.51cto.com/art/200906/132354.htm



原文:http://blog.csdn.net/luoweifu/article/details/46613015
作者:luoweifu
转载请标名出处

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 驾照被扣了3分怎么办 交警扣了行驶证怎么办 报考驾照时手机号录错怎么办 摩托车被交警队拖走怎么办 汽车牌照被偷了怎么办 代理品牌个体工商营业证怎么办 2地交社保怎么办退休 驾驶证脱审3月怎么办 a1一次性扣12分怎么办 驾照在外地掉了怎么办 在外市考的驾照怎么办 驾照过期3个月怎么办 驾照过期6个月怎么办 b本扣分了6分怎么办 b2驾照提前换证有扣分怎么办 酒驾驾驶证被扣怎么办 驾驶证被扣了分怎么办 c1驾照扣了12分怎么办 结婚证丢了怎么办离婚手续 结婚证不见了怎么办离婚手续 科目一身份丢了怎么办 考驾照身份证过期了怎么办 酒驾发交通事故致人死亡怎么办 车保险快到期了怎么办 车保险贴掉了怎么办 小车撞凹进去了怎么办 被代位追偿了怎么办 车被别人抵押了怎么办 朋友没驾照借车怎么办 车子被朋友撞了怎么办 电车被交警扣了怎么办 e照扣了12分怎么办 驾驶证被扣33分怎么办 a2驾驶员扣33分怎么办 驾驶证被扣48分怎么办 驾照扣了33分怎么办 车辆被扣36分怎么办 车被朋友借走了怎么办 在中国终身禁驾怎么办 c驾驶证忘年审了怎么办 驾驶证脱审1年多怎么办