在用法a中,当某线程执行方法xxx时,jvm会锁定该类的实例,直到方法xxx执行完毕。执行xxx的过程看看成是这样的: *请求得到类实例的实例锁,假如有其他线程在执行,则等待; *得到实例锁,执行xxx; *执行完毕,释放实例锁; 注意,这个过程是jvm完成的,我们只需要把某个对象方法声明为synchronized即可,实例锁可以理解为实例本身。 在用法b中,当某线程执行静态方法xxx时,也是有jvm控制经过以上的3个步骤,所不同的是由于此时不存在类实例(静态方法嘛),所 以用法a中实例锁被实例的类的锁取代,其实对我们编程来讲,几乎没有任何区别,我们只需要把静态方法声明为synchronized即可。 在用法c中,oLock可以被理解为一个传接棒,它可以是任何类的实例,当某个线程试图访问声明为synchronized的程序块的时候,jvm 判断oLock是否被锁定,假如没有被锁定,则锁定oLock并执行该程序块。执行完毕释放该锁。 在对象级使用锁(实例锁)通常是一种比较粗糙的方法,设想一下,假如一个对象可能去访问N个共享资源,那么假如有一个线程独占 了该对象,而仅仅是为了使用其中的一项资源的话,也会造成想访问其它资源的线程也处于堵塞状态。用程序块同步可以很好解决这个问题, 以下是使用被称为Fine_Grain_Lock的例子,看,效果是不是很high: Java代码 class FineGrainLock { MyMemberClass x, y; Object xlock = new Object(), ylock = new Object(); public void foo() { synchronized(xlock) { //access x here } //do something here - but don't use shared resources synchronized(ylock) { //access y here } }
public void bar() { synchronized(this) { //access both x and y here } //do something here - but don't use shared resources } } class FineGrainLock { MyMemberClass x, y; Object xlock = new Object(), ylock = new Object(); public void foo() { synchronized(xlock) { //access x here } //do something here - but don't use shared resources synchronized(ylock) { //access y here } } public void bar() { synchronized(this) { //access both x and y here } //do something here - but don't use shared resources } } 2.notify/wait/notifyAll,上面是交给jvm使用同步方法处理共享资源问题,可以理解为抢占型的共享资源解决方案,而使用 notify/wait/notifyall可以在程序中控制对共享资源的访问,实现一种合作型的共享资源解决方案。一个小例子: Java代码 //WNNa:wait/notify/notifyAll public class WNNa implements Runnable { private static Object oLock = new Object(); public void run() { try { synchronized(oLock) { TwoBoy t = (TwoBoy)Thread.currentThread(); if(t.getName() == "Mike") { oLock.wait(); t.eat(); oLock.notify(); oLock.wait(); t.drink(); } else { t.eat(); oLock.notify(); oLock.wait(); t.drink(); oLock.notify(); } } } catch(Exception ex) { System.out.println("Error in synchronized:" + ex.getMessage()); } } public WNNa() { TwoBoy t1 = new TwoBoy(this,"Tom"); TwoBoy t2 = new TwoBoy(this,"Mike"); t1.start(); t2.start(); } public static void main(String argv[]) { new WNNa(); } }
class TwoBoy extends Thread { private String strName = ""; public TwoBoy(Runnable t,String name) { super(t,name); strName = name; } public void drink() { System.out.println(strName + " drink!"); } public void eat() { System.out.println(strName + " eat!"); } } //WNNa:wait/notify/notifyAll public class WNNa implements Runnable { private static Object oLock = new Object(); public void run() { try { synchronized(oLock) { TwoBoy t = (TwoBoy)Thread.currentThread(); if(t.getName() == "Mike") { oLock.wait(); t.eat(); oLock.notify(); oLock.wait(); t.drink(); } else { t.eat(); oLock.notify(); oLock.wait(); t.drink(); oLock.notify(); } } } catch(Exception ex) { System.out.println("Error in synchronized:" + ex.getMessage()); } } public WNNa() { TwoBoy t1 = new TwoBoy(this,"Tom"); TwoBoy t2 = new TwoBoy(this,"Mike"); t1.start(); t2.start(); } public static void main(String argv[]) { new WNNa(); } }
class TwoBoy extends Thread { private String strName = ""; public TwoBoy(Runnable t,String name) { super(t,name); strName = name; } public void drink() { System.out.println(strName + " drink!"); } public void eat() { System.out.println(strName + " eat!"); } } 在上面的例子中,我们可以控制线程按照业务逻辑运行,而非简单的排它的使用共享资源的问题了。 3.信号量方案:在有N个共享资源而有M个线程的情况下(M>>N),需要用到信号量。信号量代表可用资源的数目,线程需要使用资源时首先判 断是否有足够的资源,没有的话等待,直到其它线程释放资源为止,得到资源后,信号量应减去该线程使用的资源数目,待这些资源使用完毕 ,线程应释放这些资源。 Java代码 class Semaphore { private int count; public Semaphore(int n) { this.count = n; }
a.方法同步,例如public synchronized void xxx()...
b.静态方法同步,例如public static synchronized void xxx()...
c.程序块同步,例如
...
synchronized(object oLock) //注意:object不一定是该类的实例
{
...
}
在用法a中,当某线程执行方法xxx时,jvm会锁定该类的实例,直到方法xxx执行完毕。执行xxx的过程看看成是这样的:
*请求得到类实例的实例锁,假如有其他线程在执行,则等待;
*得到实例锁,执行xxx;
*执行完毕,释放实例锁;
注意,这个过程是jvm完成的,我们只需要把某个对象方法声明为synchronized即可,实例锁可以理解为实例本身。
在用法b中,当某线程执行静态方法xxx时,也是有jvm控制经过以上的3个步骤,所不同的是由于此时不存在类实例(静态方法嘛),所 以用法a中实例锁被实例的类的锁取代,其实对我们编程来讲,几乎没有任何区别,我们只需要把静态方法声明为synchronized即可。
在用法c中,oLock可以被理解为一个传接棒,它可以是任何类的实例,当某个线程试图访问声明为synchronized的程序块的时候,jvm 判断oLock是否被锁定,假如没有被锁定,则锁定oLock并执行该程序块。执行完毕释放该锁。
在对象级使用锁(实例锁)通常是一种比较粗糙的方法,设想一下,假如一个对象可能去访问N个共享资源,那么假如有一个线程独占 了该对象,而仅仅是为了使用其中的一项资源的话,也会造成想访问其它资源的线程也处于堵塞状态。用程序块同步可以很好解决这个问题, 以下是使用被称为Fine_Grain_Lock的例子,看,效果是不是很high:
Java代码
class FineGrainLock {
MyMemberClass x, y;
Object xlock = new Object(), ylock = new Object();
public void foo() {
synchronized(xlock) {
//access x here
}
//do something here - but don't use shared resources
synchronized(ylock) {
//access y here
}
}
public void bar() {
synchronized(this) {
//access both x and y here
}
//do something here - but don't use shared resources
}
} class FineGrainLock {
MyMemberClass x, y;
Object xlock = new Object(), ylock = new Object();
public void foo() {
synchronized(xlock) {
//access x here
}
//do something here - but don't use shared resources
synchronized(ylock) {
//access y here
}
} public void bar() {
synchronized(this) {
//access both x and y here
}
//do something here - but don't use shared resources
}
}
2.notify/wait/notifyAll,上面是交给jvm使用同步方法处理共享资源问题,可以理解为抢占型的共享资源解决方案,而使用 notify/wait/notifyall可以在程序中控制对共享资源的访问,实现一种合作型的共享资源解决方案。一个小例子:
Java代码
//WNNa:wait/notify/notifyAll
public class WNNa implements Runnable
{
private static Object oLock = new Object();
public void run()
{
try
{
synchronized(oLock)
{
TwoBoy t = (TwoBoy)Thread.currentThread();
if(t.getName() == "Mike")
{
oLock.wait();
t.eat();
oLock.notify();
oLock.wait();
t.drink();
}
else
{
t.eat();
oLock.notify();
oLock.wait();
t.drink();
oLock.notify();
}
}
}
catch(Exception ex)
{
System.out.println("Error in synchronized:" + ex.getMessage());
}
}
public WNNa()
{
TwoBoy t1 = new TwoBoy(this,"Tom");
TwoBoy t2 = new TwoBoy(this,"Mike");
t1.start();
t2.start();
}
public static void main(String argv[])
{
new WNNa();
}
}
class TwoBoy extends Thread
{
private String strName = "";
public TwoBoy(Runnable t,String name)
{
super(t,name);
strName = name;
}
public void drink()
{
System.out.println(strName + " drink!");
}
public void eat()
{
System.out.println(strName + " eat!");
}
} //WNNa:wait/notify/notifyAll
public class WNNa implements Runnable
{
private static Object oLock = new Object();
public void run()
{
try
{
synchronized(oLock)
{
TwoBoy t = (TwoBoy)Thread.currentThread();
if(t.getName() == "Mike")
{
oLock.wait();
t.eat();
oLock.notify();
oLock.wait();
t.drink();
}
else
{
t.eat();
oLock.notify();
oLock.wait();
t.drink();
oLock.notify();
}
}
}
catch(Exception ex)
{
System.out.println("Error in synchronized:" + ex.getMessage());
}
}
public WNNa()
{
TwoBoy t1 = new TwoBoy(this,"Tom");
TwoBoy t2 = new TwoBoy(this,"Mike");
t1.start();
t2.start();
}
public static void main(String argv[])
{
new WNNa();
}
}
class TwoBoy extends Thread
{
private String strName = "";
public TwoBoy(Runnable t,String name)
{
super(t,name);
strName = name;
}
public void drink()
{
System.out.println(strName + " drink!");
}
public void eat()
{
System.out.println(strName + " eat!");
}
}
在上面的例子中,我们可以控制线程按照业务逻辑运行,而非简单的排它的使用共享资源的问题了。
3.信号量方案:在有N个共享资源而有M个线程的情况下(M>>N),需要用到信号量。信号量代表可用资源的数目,线程需要使用资源时首先判 断是否有足够的资源,没有的话等待,直到其它线程释放资源为止,得到资源后,信号量应减去该线程使用的资源数目,待这些资源使用完毕 ,线程应释放这些资源。
Java代码
class Semaphore {
private int count;
public Semaphore(int n) {
this.count = n;
}
public synchronized void acquire() {
while(count == 0) {
try {
wait();
} catch (InterruptedException e) {
//keep trying
}
}
count--;
}
public synchronized void release() {
count++;
notify(); //alert a thread that's blocking on this semaphore
}
}