深入理解synchronized关键字

全文概要

本文主要介绍JAVA线程中synchronized关键字的用法。对于synchronized关键字主要包含以下几点:
  • 当一个线程访问某一个对象synchronized修饰的非静态方法或者代码块时,其他线程不允许访问该对象synchronized修饰的相同的方法或者代码块;
  • 当一个线程访问某一个对象synchronized修饰的非静态方法或者代码块时,其他线程不允许访问该对象synchronized修饰的其他的非静态方法或者代码块;
  • 当一个线程访问某一个对象synchronized修饰的方法或者代码块时,其他线程允许访问该对象的非synchronized修饰的方法或者代码块;
  • 当一个线程访问某一个对象synchronized修饰的方法或者代码块时,其他线程允许访问其他对象synchronized修饰的非静态方法或者代码块;
  • 当一个线程访问某一个对象synchronized修饰的非静态方法或者代码块时,其他线程允许访问该对象synchronized修饰的静态方法或者代码块;
  • 当一个线程访问同一个字节码对象的synchronized修饰的静态方法或者代码块时,其他线程不允许访问该节码对象的所有的synchronized修饰的静态方法或者代码块

synchronized关键字用法

验证第一点
  • 代码案例
package com.tml.javaCore.thread.sync;

/**
 * <p>多线程
 * @author Administrator
 *
 */
public class SynchronizedDemo1 {
	public static void main(String[] args) {
		SynchronizedDemo1 demo  = new  SynchronizedDemo1();
		
		Thread t1 = new  Thread(new Runnable() {
			public void run() {
				demo.print();
			}
		}, "t1");
		
		Thread t2 = new  Thread(new Runnable() {
			public void run() {
				demo.print();
			}
		}, "t2");
		
		t1.start();
		t2.start();

	}

	private synchronized void print() {
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is running ....!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}
}
  • 输出结果
 t1 is running ....!
 t1 is running ....!
 t1 is running ....!
 t1 is running ....!
 t1 is running ....!
 t2 is running ....!
 t2 is running ....!
 t2 is running ....!
 t2 is running ....!
 t2 is running ....!

  • 结果说明
 线程1和线程2都是调用SynchronizedDemo1对象的print()方法,线程1执行时,线程2阻塞。
验证第二点
  • 代码案例
package com.tml.javaCore.thread.sync;

/**
 * <p>多线程
 * @author Administrator
 *
 */
public class SynchronizedDemo2 {
	public static void main(String[] args) {
		SynchronizedDemo2 demo  = new  SynchronizedDemo2();
		
		Thread t1 = new  Thread(new Runnable() {
			public void run() {
				demo.print();
			}
		}, "t1");
		
		Thread t2 = new  Thread(new Runnable() {
			public void run() {
				demo.read("hello world!");
			}
		}, "t2");
		
		t1.start();
		t2.start();

	}

	private synchronized void print() {
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is running ....!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}
	
	
	private synchronized  void read(String name) {
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is reading :" + name );
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}
}
  • 输出结果
 t1 is running ....!
 t1 is running ....!
 t1 is running ....!
 t1 is running ....!
 t1 is running ....!
 t2 is reading :hello world!
 t2 is reading :hello world!
 t2 is reading :hello world!
 t2 is reading :hello world!
 t2 is reading :hello world!

  • 结果说明
 线程1调用demo的print()方法,线程2调用demo的read()方法,虽然方法不同,但都是公用一个同步锁,所以线程1执行时,线程2阻塞。
验证第三点
  • 代码案例
package com.tml.javaCore.thread.sync;

/**
 * <p>多线程
 * @author Administrator
 *
 */
public class SynchronizedDemo3 {
	public static void main(String[] args) {
		SynchronizedDemo3 demo  = new  SynchronizedDemo3();
		
		Thread t1 = new  Thread(new Runnable() {
			public void run() {
				demo.print();
			}
		}, "t1");
		
		Thread t2 = new  Thread(new Runnable() {
			public void run() {
				demo.write("hello world!");
			}
		}, "t2");
		
		t1.start();
		t2.start();

	}

	private  void print() {
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is running ....!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}
	
	
	private synchronized void write(String name) {
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is writing :" + name );
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}
}
  • 输出结果
 t1 is running ....!
 t2 is writing :hello world!
 t2 is writing :hello world!
 t1 is running ....!
 t2 is writing :hello world!
 t1 is running ....!
 t1 is running ....!
 t2 is writing :hello world!
 t2 is writing :hello world!
 t1 is running ....!

  • 结果说明
 print()方法为非同步方法,不会占用对象锁,所以线程1和线程2同时执行。
验证第四点
  • 代码案例
package com.tml.javaCore.thread.sync;

/**
 * <p>多线程
 * @author Administrator
 *
 */
public class SynchronizedDemo4 {
	public static void main(String[] args) {
		SynchronizedDemo4 demo  = new  SynchronizedDemo4();
		SynchronizedDemo4 demo1  = new  SynchronizedDemo4();
		
		Thread t1 = new  Thread(new Runnable() {
			public void run() {
				demo.print();
			}
		}, "t1");
		
		Thread t2 = new  Thread(new Runnable() {
			public void run() {
				demo1.print();
			}
		}, "t2");
		
		
		t1.start();
		t2.start();

	}

	private synchronized void print() {
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is running ....!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

	
}
  • 输出结果
 t2 is running ....!
 t1 is running ....!
 t2 is running ....!
 t1 is running ....!
 t2 is running ....!
 t1 is running ....!
 t1 is running ....!
 t2 is running ....!
 t2 is running ....!
 t1 is running ....!

  • 结果说明
 线程1和线程2的对象锁不一样,所以线程1和线程2同时执行。
验证第五点
  • 代码案例
package com.tml.javaCore.thread.sync;

/**
 * <p>多线程
 * @author Administrator
 *
 */
public class SynchronizedDemo5 {
	public static void main(String[] args) {
		SynchronizedDemo5 demo  = new  SynchronizedDemo5();
		
		Thread t1 = new  Thread(new Runnable() {
			public void run() {
				/*
				 * 调用非静态方法
				 */
				demo.print();
				
			}
		}, "t1");
		
		Thread t2 = new  Thread(new Runnable() {
			public void run() {
				demo.staticPrint();//用对象调用静态方法,不规范,会有警告,建议用下面的方法
				//SynchronizedDemo5.staticPrint();
			}
		}, "t2");
		
		
		t1.start();
		t2.start();

	}

	private synchronized void print() {
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is print running ....!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}
	
	

	

	/*
	 * 静态同步方法
	 */
	private synchronized static void staticPrint(){
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is staticPrint running ....!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	

	
}
  • 输出结果
 t2 is staticPrint running ....!
 t1 is print running ....!
 t2 is staticPrint running ....!
 t1 is print running ....!
 t1 is print running ....!
 t2 is staticPrint running ....!
 t2 is staticPrint running ....!
 t1 is print running ....!
 t1 is print running ....!
 t2 is staticPrint running ....!

  • 结果说明
 线程1和线程2虽然都是调用demo对象的方法,但是print()为非静态同步方法,而staticPrint()为静态同步方法,根本原因
是对象锁不一样。非静态方法的同步锁为demo,而静态方法的同步锁为SynchronizedDemo5.class
验证第六点
  • 代码案例
package com.tml.javaCore.thread.sync;

/**
 * <p>多线程
 * @author Administrator
 *
 */
public class SynchronizedDemo6 {
	public static void main(String[] args) {
		
		Thread t1 = new  Thread(new Runnable() {
			public void run() {
				SynchronizedDemo6.staticPrint();
				
			}
		}, "t1");
		
		Thread t2 = new  Thread(new Runnable() {
			public void run() {
				SynchronizedDemo6.staticPrint1();
			}
		}, "t2");
		
		
		t1.start();
		t2.start();

	}

	@SuppressWarnings("unused")
	private synchronized void print() {
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is print running ....!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}
	
	
	@SuppressWarnings("unused")
	private  void print1() {
		synchronized (this) {
			for(int i=0;i<5;i++){
				try {
					Thread.sleep(500);
					System.out.println(Thread.currentThread().getName() + " is print1 running ....!");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		

	}
	

	/*
	 * 静态同步方法
	 */
	private synchronized static void staticPrint(){
		for(int i=0;i<5;i++){
			try {
				Thread.sleep(500);
				System.out.println(Thread.currentThread().getName() + " is staticPrint running ....!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	
	private  static void staticPrint1(){
		/*
		 * 静态同步代码块
		 */
		synchronized (SynchronizedDemo6.class) {
			for(int i=0;i<5;i++){
				try {
					Thread.sleep(500);
					System.out.println(Thread.currentThread().getName() + " is staticPrint1 running ....!");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
	
}
  • 输出结果
 t1 is staticPrint running ....!
 t1 is staticPrint running ....!
 t1 is staticPrint running ....!
 t1 is staticPrint running ....!
 t1 is staticPrint running ....!
 t2 is staticPrint1 running ....!
 t2 is staticPrint1 running ....!
 t2 is staticPrint1 running ....!
 t2 is staticPrint1 running ....!
 t2 is staticPrint1 running ....!

  • 结果说明
 对于静态方法,他的同步锁是 该类的字节码对象,该对象在java内存中只有一份,例如,staticPrint()和staticPrint1()方法的同步锁一样。而非静态方法可以使用 this来作为同步锁,this表示当前对象。例如,print()和print1()方法的同步锁一样。很多单例方法都使用字节码对象锁,确保该类只有一个实例。





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值