深入理解synchronized关键字的用法 _JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 深入理解synchronized关键字的用法

深入理解synchronized关键字的用法

 2019/1/8 15:37:33  ninghq  程序员俱乐部  我要评论(0)
  • 摘要:内置锁:每个java对象都可以用做一个实现同步的锁,这些锁称为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。互斥锁:内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。synchronized既是内置锁也是互斥锁synchronized三种修饰第一
  • 标签:

?

?内置锁:每个java对象都可以用做一个实现同步的锁,这些锁称为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。

? 互斥锁:内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。 ? synchronized既是内置锁也是互斥锁 ? synchronized三种修饰 第一、修饰普通方法 代码示例:
class="代码示例:" name="code">public class TestSynchronized {
    
	public synchronized void out() throws InterruptedException {
	  System.out.println("test开始..");  
      try {  
          Thread.sleep(5000L);  
      } catch (InterruptedException e) {  
          e.printStackTrace();  
      }  
      System.out.println("test结束..");
	}
	
	public static void main(String[] args) {
		TestSynchronized testSync = new TestSynchronized();
		TestSynchronized testSync2 = new TestSynchronized();
		
		new Thread(() -> {
			try {
				testSync.out();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();
		
		new Thread(() -> {
			try {
				testSync2.out();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();
		
	}

}
?控制台输出:
test开始..
test开始..
test结束..
test结束..
?很明显,synchronized修饰普通方法的时候,锁住的是对象的实例,代码示例中,testSync 和testSync2分别都是TestSynchronized对象的实例,他们两个都可以同时进入synchronized修饰的普通方法,所以得出,synchronized修饰普通方法的时候,锁住的是对象的实例。 第二、修饰静态方法 代码示例:
public class TestSynchronized {

    	public static synchronized void staticOut() throws InterruptedException {
		long startTime = System.currentTimeMillis();  
		System.out.println("test开始..");  
	      try {  
	          Thread.sleep(5000L);  
	      } catch (InterruptedException e) {  
	          e.printStackTrace();  
	      }  
	      System.out.println("test结束..");
	      long endTime = System.currentTimeMillis();
	      System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms");
		}
	
	public static void main(String[] args) {
		TestSynchronized testSync = new TestSynchronized();
		TestSynchronized testSync2 = new TestSynchronized();
		
		new Thread(() -> {
			try {
				testSync.staticOut();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();
		
		new Thread(() -> {
			try {
				testSync2.staticOut();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();
		
	}

}
?控制台输出:
test开始..
test结束..
线程Thread-0程序运行时间:5000ms
test开始..
test结束..
线程Thread-1程序运行时间:5000ms
?可以看出,synchronized修饰静态方法的时候,起到了锁的作用,线程分别获得锁后才进入静态方法中,但是尽量不要使用synchronized修饰静态方法,因为它锁住的是整个类,也就是说,在整个类中的其他synchronized修饰的方法都会被锁住。 示例代码如下:
public class TestSynchronized {
   
	public static synchronized void staticOut() throws InterruptedException {
		long startTime = System.currentTimeMillis();  
		System.out.println("test开始..");  
	      try {  
	          Thread.sleep(5000L);  
	      } catch (InterruptedException e) {  
	          e.printStackTrace();  
	      }  
	      System.out.println("test结束..");
	      long endTime = System.currentTimeMillis();
	      System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms");
	}
	
	
	public static synchronized void staticOut2() throws InterruptedException {
		long startTime = System.currentTimeMillis();  
		System.out.println("test2开始..");  
	      try {  
	          Thread.sleep(5000L);  
	      } catch (InterruptedException e) {  
	          e.printStackTrace();  
	      }  
	      System.out.println("test2结束..");
	      long endTime = System.currentTimeMillis();
	      System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms");
	}
	
	public static void main(String[] args) {
		TestSynchronized testSync = new TestSynchronized();
		TestSynchronized testSync2 = new TestSynchronized();
		
		new Thread(() -> {
			try {
				testSync.staticOut();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();
		
		new Thread(() -> {
			try {
				testSync2.staticOut2();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();
		
	}

}
?控制台输出:
test开始..
test结束..
线程Thread-0程序运行时间:5000ms
test2开始..
test2结束..
线程Thread-1程序运行时间:5001ms
?可以看出,线程Thread-0进入synchronized修饰的静态方法staticOut()的时候,这个类就被锁住了,线程Thread-1无法获得锁,只能等待锁的释放后才能进入方法staticOut2()。所以使用synchronized修饰静态方法需要慎重。 ? 第三、修饰代码块 示例代码:
public class TestSynchronized {

	private Object lock = new Object();
	public void lockOut(){
		synchronized(lock){
			long startTime = System.currentTimeMillis();  
			System.out.println("test开始..");  
		    try {  
		        Thread.sleep(5000L);  
		    } catch (InterruptedException e) {  
		        e.printStackTrace();  
		    }  
		    System.out.println("test结束..");
		    long endTime = System.currentTimeMillis();
		    System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms");
			
		}
	}
	
	public static void main(String[] args) {
		TestSynchronized testSync = new TestSynchronized();
		TestSynchronized testSync2 = new TestSynchronized();
		
		new Thread(() -> {
			testSync.lockOut();
		}).start();
		
		new Thread(() -> {
			testSync2.lockOut();
		}).start();
		
	}
}
?控制台输出:
test开始..
test开始..
test结束..
test结束..
线程Thread-0程序运行时间:5000ms
线程Thread-1程序运行时间:5000ms
?synchronized修饰代码块时,锁住的是一个对象 synchronized (lock) 即synchronized后面括号里的内容,因为两个对象创建了两个不同对象实例lock,所以两个对象的线程都可以同时进入synchronized修饰代码块。如果想锁住synchronized修饰的代码块,只需要确定synchronized后面括号里锁住同一 对象即可,常用的方法如下: 1、synchronized锁这个类对应的Class对象。 实例代码:
public class TestSynchronized {
    
//	private Object lock = new Object();
	public void lockOut(){
		synchronized(TestSynchronized.class){
			long startTime = System.currentTimeMillis();  
			System.out.println("test开始..");  
		    try {  
		        Thread.sleep(5000L);  
		    } catch (InterruptedException e) {  
		        e.printStackTrace();  
		    }  
		    System.out.println("test结束..");
		    long endTime = System.currentTimeMillis();
		    System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms");
			
		}
	}
	
	public static void main(String[] args) {
		TestSynchronized testSync = new TestSynchronized();
		TestSynchronized testSync2 = new TestSynchronized();
		
		new Thread(() -> {
			testSync.lockOut();
		}).start();
		
		new Thread(() -> {
			testSync2.lockOut();
		}).start();
		
	}

}
?控制台输出:
test开始..
test结束..
线程Thread-0程序运行时间:5001ms
test开始..
test结束..
线程Thread-1程序运行时间:5002ms
?让synchronized锁这个类对应的Class对象这种方法实现了全局锁的效果,和synchronized修饰静态方法一样(static synchronized方法也是相当于全局锁),整个类就被锁住了,所以此方法一样需要慎重使用。 2、创建一个单例对象,锁住的是该单例对象,单例对象只有一个实例。
public class TestSynchronized {
 
	private volatile static Object lock = new Object(); 
	public void lockOut(){
		synchronized(lock){
                        System.out.println("指针地址:" + lock.toString());  
			long startTime = System.currentTimeMillis();  
			System.out.println("test开始..");  
		    try {  
		        Thread.sleep(5000L);  
		    } catch (InterruptedException e) {  
		        e.printStackTrace();  
		    }  
		    System.out.println("test结束..");
		    long endTime = System.currentTimeMillis();
		    System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms");
			
		}
	}
	
	public static void main(String[] args) {
		TestSynchronized testSync = new TestSynchronized();
		TestSynchronized testSync2 = new TestSynchronized();
		
		new Thread(() -> {
			testSync.lockOut();
		}).start();
		
		new Thread(() -> {
			testSync2.lockOut();
		}).start();
		
	}

}
?控制台输出:
指针地址:java.lang.Object@ce407e7
test开始..
test结束..
线程Thread-0程序运行时间:1000ms
指针地址:java.lang.Object@ce407e7
test开始..
test结束..
线程Thread-1程序运行时间:1001ms
?保证了单例对象lock 的实例唯一性,synchronized锁住同一个固定对象,从控制台上可以看出,访问代码块的对象指针地址是一样的。 ? 3、访问该代码块的对象唯一 示例代码:
public class TestSynchronized {
	
//	private volatile static Object lock = new Object(); 
	
	public void lockOut(){
		synchronized(this){
                        System.out.println("指针地址:" + this.toString());  
			long startTime = System.currentTimeMillis();  
			System.out.println("test开始..");  
		    try {  
		        Thread.sleep(1000);  
		    } catch (InterruptedException e) {  
		        e.printStackTrace();  
		    }  
		    System.out.println("test结束..");
		    long endTime = System.currentTimeMillis();
		    System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms");
			
		}
	}
	
	public static void main(String[] args) {
		TestSynchronized testSync = new TestSynchronized();
		
			new Thread(() -> {
				testSync.lockOut();
			}).start();
			
			new Thread(() -> {
				testSync.lockOut();
			}).start();
		}

}
?控制台输出:
指针地址:com.test.test.TestSynchronized@1dca18a4
test开始..
test结束..
线程Thread-0程序运行时间:1000ms
指针地址:com.test.test.TestSynchronized@1dca18a4
test开始..
test结束..
线程Thread-1程序运行时间:1000ms
?synchronized后面括号的this指的是访问该代码块的对象,从控制台上可以看出,访问代码块的对象指针地址是一样的,从而可以得出他们是固定同一对象。
  • 相关文章
发表评论
用户名: 匿名