首页 > 代码库 > synchronized关键字

synchronized关键字

public class ThreadSafe
{

	public static void main(String[] args)
	{
		Safe safe = new Safe();
		new Thread(new Runnable()
		{

			public void run()
			{
				try
				{
					while (true)
					{
						safe.setI(100);
						
					}
				}
				catch (InterruptedException e)
				{
					e.printStackTrace();
				}
			}
		}).start();
		new Thread(new Runnable()
		{

			public void run()
			{
				while (true)
				{
					try
					{
						safe.getI();
						
					}
					catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
}

class Safe
{
	int i;
	public Safe()
	{
		this.i = 0;
	}

	public synchronized void setI(int i) throws InterruptedException
	{
		System.out.println("setId"+" "+i);
		Thread.sleep(1000 * 3);
		System.out.println("backsetId"+" "+100);
		this.i = i;
	}

	public synchronized int getI() throws InterruptedException
	{
		System.out.println("getId"+" "+i);
		this.i=10;
		Thread.sleep(1000 * 3);
		System.out.println("backgetId"+" "+10);
		return this.i;
	}
}

  输出:

setId 100
backsetId 100
getId 100
backgetId 10
setId 100
backsetId 100
setId 100

synchronized在方法声明中,锁的是this,

在jvm汇编指令里面并没有显式的出现monitorenter

下面代码

public class ThreadSafe
{

	public static void main(String[] args)
	{
		Safe safe = new Safe();
		new Thread(new Runnable()
		{

			public void run()
			{
				try
				{
					while (true)
					{
						safe.setI(100);

					}
				}
				catch (InterruptedException e)
				{
					e.printStackTrace();
				}
			}
		}).start();
		new Thread(new Runnable()
		{

			public void run()
			{
				while (true)
				{
					try
					{
						safe.getI();

					}
					catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
}

class Safe
{
	int i;

	public Safe()
	{
		this.i = 0;
	}

	public synchronized void setI(int i) throws InterruptedException
	{
		System.out.println("setId" + " " + i);
		Thread.sleep(1000 * 3);
		System.out.println("backsetId" + " " + 100);
		this.i = i;
	}

	public int getI() throws InterruptedException
	{
		synchronized (this)
		{
			System.out.println("getId" + " " + i);
			this.i = 10;
			Thread.sleep(1000 * 3);
			System.out.println("backgetId" + " " + 10);
		}
		return this.i;
	}
}

  执行结果一样

 public synchronized void setI(int) throws java.lang.InterruptedException;
   Code:
      0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      3: new           #4                  // class java/lang/StringBuilder
      6: dup
      7: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
     10: ldc           #6                  // String setId
     12: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     15: iload_1
     16: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
     19: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     22: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     25: ldc2_w        #11                 // long 3000l
     28: invokestatic  #13                 // Method java/lang/Thread.sleep:(J)V
     31: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
     34: ldc           #14                 // String backsetId 100
     36: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     39: aload_0
     40: iload_1
     41: putfield      #2                  // Field i:I
     44: return

 public int getI() throws java.lang.InterruptedException;
   Code:
      0: aload_0
      1: dup
      2: astore_1
      3: monitorenter  进入管程
      4: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      7: new           #4                  // class java/lang/StringBuilder
     10: dup
     11: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
     14: ldc           #15                 // String getId
     16: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     19: aload_0
     20: getfield      #2                  // Field i:I
     23: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
     26: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     29: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     32: aload_0
     33: bipush        10
     35: putfield      #2                  // Field i:I
     38: ldc2_w        #11                 // long 3000l
     41: invokestatic  #13                 // Method java/lang/Thread.sleep:(J)V
     44: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
     47: ldc           #16                 // String backgetId 10
     49: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     52: aload_1
     53: monitorexit  退出管程
     54: goto          62
     57: astore_2
     58: aload_1
     59: monitorexit
     60: aload_2
     61: athrow
     62: aload_0
     63: getfield      #2                  // Field i:I
     66: ireturn
   Exception table:
      from    to  target type
          4    54    57   any
         57    60    57   any

注意有个方法出现了进入管程指令,退出管程指令,有个方法没有

来自java虚拟机规范的解释

Java 虚拟机可以支持方法级的同步和方法内部一段指令序列的同步,这两种同步结构都是使用管程( Monitor)来支持的。方法级的同步是隐式,即无需通过字节码指令来控制的,它实现在方法调用和返回操作( §2.11.8)之中。
虚拟机可以从方法常量池中的方法表结构( method_info Structure, §4.6)中的 ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法。当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先持有管程,然后再执行方法,最后再方法完成(无论是正常完成还是非正常完成)时释放管程。在方法执行期
间,执行线程持有了管程,其他任何线程都无法再获得同一个管程。如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那这个同步方法所持有的管程将在异常抛到同步方法之外时自动释放

monitor和对象的关系.来自jvm文档

monitor 即可以实现为与对象一同分配
和销毁,也可以在某条线程尝试获取对象所有权时动态生成,在没有任何线程
持有对象所有权时自动释放。
实际上synchoronized关键字修饰方法的时候就是进入对象的monitor,所以第一个代码会出现in-out一组一组的出现,而不会出现in-in2-out这种组合

 

synchronized关键字