标签:
同步代码块是一种有效实现操作原子性的方法,上一章我们讲了一些同步的原子操作的基础。
现在我们回忆一下上一章的两个问题。
1:不同的synchronized的写法有什么区别,又该怎么写创建线程的代码呢?
以class实例对象作为锁的写法
写法1
package com.home.thread; /** * @author gaoxu * */ public class SafeThread { @safe public void testPrint(){ synchronized(SafeThread.class){ System.out.println("Enter testPrint method !"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Exit testPrint method !"); } } }
写法2
package com.home.thread; /** * @author gaoxu * */ public class SafeThread { public static synchronized void testPrint(){ System.out.println("Enter testPrint method !"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Exit testPrint method !"); } }
以上两种写法是以class实例对象为锁的写法,这两种写法的调用线程该怎么写呢?让我们来看下面的例子
写法1,创建当前对象实例,并使用对象实例初始化线程。
package com.home.thread; /** * @author gaoxu * */ public class ThreadStart { public static void main(String[] para){ SafeThread safe = new SafeThread(); for(int i=0;i<3;i++){ ThreadRead1 t1 = new ThreadRead1(safe); t1.start(); } } }
package com.home.thread; /** * @author gaoxu * */ public class ThreadRead1 extends Thread{ SafeThread safe = null; public ThreadRead1(){ } public ThreadRead1(SafeThread o){ safe = o; } public void run() { safe.testPrint(); } }
写法2,可以在线程中创建类实例。
package com.home.thread; /** * @author gaoxu * */ public class ThreadStart { public static void main(String[] para){ for(int i=0;i<3;i++){ ThreadRead1 t1 = new ThreadRead1(); t1.start(); } } }</span>
<span style="font-size:14px;">package com.home.thread; /** * @author gaoxu * */ public class ThreadRead1 extends Thread{ SafeThread safe = null; public ThreadRead1(){ } public void run() { safe = new SafeThread(); safe.testPrint(); } }
这两总写法可以起到相同的作用,都可以实现原子的操作,实现同步互斥的调用。
创建内部同步代码块,以当前实例对象作为锁的对象。
写法1
package com.home.thread; /** * @author gaoxu * */ public class SafeThread { public synchronized void testPrint(){ System.out.println("Enter testPrint method !"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Exit testPrint method !"); } }
package com.home.thread; /** * @author gaoxu * */ public class SafeThread { public void testPrint(){ synchronized(this){ System.out.println("Enter testPrint method !"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Exit testPrint method !"); } } }<span style="font-size:14px;"> </span>
package com.home.thread; /** * @author gaoxu * */ public class SafeThread { Object a = new Object(); public void testPrint(){ synchronized(a){ System.out.println("Enter testPrint method !"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Exit testPrint method !"); } } }
这三种写法都是以类的当前实例对象作为锁对象,所以线程调用写法如下;
package com.home.thread; /** * @author gaoxu * */ public class ThreadStart { public static void main(String[] para){ SafeThread safe = new SafeThread();//当前实例对象 for(int i=0;i<3;i++){ ThreadRead1 t1 = new ThreadRead1(safe); t1.start(); } } }
package com.home.thread; /** * @author gaoxu * */ public class ThreadRead1 extends Thread{ SafeThread safe = null; public ThreadRead1(){ } public ThreadRead1(SafeThread o){ safe = o; } public void run() { safe.testPrint(); } }
下面让我们来看一下以class对象和当前对象的区别:
类.class和static synchronized是对该类所有实例对象枷锁。
synchronized(this),synchronized,synchronized(object)都是对类的当前实例对象加锁。
具体说明:
synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的当前实例的所有synchronized块。static synchronized是控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例对应的代码快。在类中某方法或某代码块中有 synchronized,那么在生成一个该类实例后,该类也就有一个监视块,放置线程并发访问该实例synchronized保护块,这个保护块只对当前实例有效,而static
synchronized则是所有该类的实例公用一个监视块,放置线程并发访问该类所有实例的保护块,synchronized相当于 this.synchronized,而
static synchronized相当于Something.synchronized。
2:死锁、活跃性问题都是怎么产生的。
后续章节我们重点讨论。
j今天的问题是:
1:线程安全除了原子操作还有什么需要注意的。
2:如何确定自己需要实现一个线程安全类。
标签:
原文地址:http://blog.csdn.net/andy_gx/article/details/42932913