线程同步之synchronized关键字简单使用分析、示例

声明

  1. 本人测试代码,放在本文末尾,复制可用
  2. 为方便说明,前面主要以图片为主,进行示例

synchronized关键字实现线程同步的方式有

  1. 使用同步方法

  2. 使用同步代码块儿

 

关键概念说明

        任何Object都有且仅有一个属于它自己的内置锁,这个内置锁是互斥的;当线程需要访问这个Objcet的任何一个需要内置锁的方法或任何一个指定需要这个Objcet的内置锁的同步代码块儿时,这个线程必须先抢占到这个Object的内置锁才能访问。当同步方法或同步代码块儿执行完毕之后,马上释放这个对象的锁,再进行新的一轮的抢占。  

注:synchronized关键字修饰的方法或代码块儿,就表示访问时需要内置锁

注:同步方法释放锁的时机是:该同步方法执行完毕;

同步代码块儿释放锁的时机是:该同步代码块儿执行完毕(无论该同步代码块儿所在的方法是否执行完毕)。

 

按照Object不同,我们一般又分为对象锁与类锁(注:类锁只是一个抽象性概念)

注:一个有且只有一个属于自己的类锁;如果一个类实例了多个对象,那么每个对象有且只有一个属于它们自己的对象锁

注:如果一个对象锁或者类锁被某一个线程抢占到了,并不会影响其他线程访问这个对象或这个类的那些没有被锁上(没有synchronized关键字)的方法、没有被锁上(没有synchronized关键字)的代码块儿

注:类锁与对象锁并不互斥,即:一个线程获得了一个类的一个实例对象的对象锁,那么并不影响其他线程获得该类的类锁

 

使用时,代码总体说明

需要类锁的情况

1.synchronized作用在静态方法上

2.synchronized用于同步代码块儿,但是指定类锁

需要对象锁的情况

1.synchronized作用在普通方法上

2.synchronized用于同步代码块儿,但是指定这个对象

使用synchronized代码块儿指定获取某个值非null的Object(不限于类、实例等)的锁

 

使用时,代码详细说明

先看一下MyThread类的继承实现关系,为下面做铺垫:

代码详细说明正式开始

调用被synchronized修饰的静态方法---[测试类锁]

要被调用的方法:

main测试方法:

某次输出结果为:

注:这两个方法都需要同一个锁,所以线程就会进行抢占、就会发生线程等待、堵塞等情况。(为了快速测试,本人只写了一个被synchronized修饰的静态方法来测试)。

注:不论多个线程要调用的方法是不是同一个被synchronized修饰的方法、是不是同一个被synchronized修饰的代码块儿所处的方法是被synchronized修饰的方法还是被synchronized修饰的代码块儿所处的方法,只要多个线程同时需要同一个锁时,线程就会进行抢占、就会发生线程等待、堵塞等情况

 

synchronized用于同步代码块儿,但是指定类锁---[测试类锁]

要被调用的方法:

main测试方法:

某次输出结果为:

注:由于这个类的实例方法synchronizedCodeBlockTest4中的代码块儿指定了需要类锁,而静态方法也需要类锁,所以这里线程就需要抢占、就会发生线程等待、堵塞等情况。

注:不论多个线程要调用的方法是不是同一个被synchronized修饰的方法、是不是同一个被synchronized修饰的代码块儿所处的方法是被synchronized修饰的方法还是被synchronized修饰的代码块儿所处的方法,只要多个线程同时需要同一个锁时,线程就会进行抢占、就会发生线程等待、堵塞等情况

 

synchronized作用在普通方法上---[测试对象锁]

要被调用的方法:

main测试方法:

某次输出结果为:

注:测试对象锁时,创建线程要用同一个对象来创建.因为:一个类的不同实例对象,都有一个属于自己的对象锁,我们要测试,就需要同一个对象来创建线程

注:不论多个线程要调用的方法是不是同一个被synchronized修饰的方法、是不是同一个被synchronized修饰的代码块儿所处的方法是被synchronized修饰的方法还是被synchronized修饰的代码块儿所处的方法,只要多个线程同时需要同一个锁时,线程就会进行抢占、就会发生线程等待、堵塞等情况

 

synchronized用于同步代码块儿,但是指定对象锁---[测试对象锁]

要被调用的方法:

main测试方法:

某次输出结果为:

注:测试对象锁时,创建线程要用同一个对象来创建.因为:一个类的不同实例对象,都有一个属于自己的对象锁,我们要测试,就需要同一个对象来创建线程

注:不论多个线程要调用的方法是不是同一个被synchronized修饰的方法、是不是同一个被synchronized修饰的代码块儿所处的方法是被synchronized修饰的方法还是被synchronized修饰的代码块儿所处的方法,只要多个线程同时需要同一个锁时,线程就会进行抢占、就会发生线程等待、堵塞等情况

 

测试同步代码块儿 ,抢占锁的时机

要被调用的方法:

main测试方法:

多次运行main方法,其中两次输出结果:

某一次输出:

某一次输出:

注:synchronized修饰方法时,在进入方法时,就需要锁;方法执行完毕之后,才释放锁

注:这里是以需要对象锁的代码块儿测试的,经测试,需要类象锁的代码块儿也遵循此原则

注:synchronized修饰同步代码块儿时,在进入代码块儿所在的方法时,暂时不需要锁;但是在执行到该代码块儿时,需要放锁,当代码块儿执行完毕之后,马上释放锁(无论此时代码块儿所在的方法是否执行完)

 

测试同步代码块儿 ,释放锁的时机

要被调用的方法:

main测试方法:

某次输出结果为:

注:synchronized修饰方法时,在进入方法时,就需要锁;方法执行完毕之后,才释放锁

注:这里是以需要对象锁的代码块儿测试的,经测试,需要类象锁的代码块儿也遵循此原则

注:synchronized修饰同步代码块儿时,在进入代码块儿所在的方法时,暂时不需要锁;但是在执行到该代码块儿时,需要放锁,当代码块儿执行完毕之后,马上释放锁(无论此时代码块儿所在的方法是否执行完)

 

使用synchronized代码块儿指定获取某个值非null的Object(不限于类、实例等)的锁

要被调用的方法:

main函数为:

某次输出结果为:

注:我们使用关键字synchronized时,一般指明都是指明需要对象或类的锁;但有时这样并不能满足我们的需求,此时我们就可以考虑使用上述方式。

再如:

此时,synchronized (hashtable)就意味着,需要抢占对象锁或者抢占类锁了。具体哪些同步方法、哪些同步代码块儿需要锁,这里就不再赘述了。

 

类锁与对象锁 互不影响 --- 测试

要被调用的方法:

 

main函数为:

某次输出结果为:

注:我们使用关键字synchronized时,一般指明都是指明需要对象或类的锁;但有时这样并不能满足我们的需求,此时我们就可以考虑使用上述方式。

 

给出本次测试代码

/**
 * 多线程synchronized关键字---使用测试
 *
 * @author JustryDeng
 * @Date 2018年8月27日 上午11:06:40
 */
public class MyThread implements Runnable {



	/**
	 * 同步方法:synchronized作用在普通方法上(需要这个类的实例对象的对象锁)
	 *
	 * @Date 2018年8月27日 下午4:47:16
	 */
	public synchronized void synchronizedMethodTest1() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "\t" + i);
		}
	}

	/**
	 * 同步方法:synchronized作用在静态方法上(需要这个类的类锁)
	 *
	 * @Date 2018年8月27日 下午4:47:16
	 */
	public static synchronized void synchronizedMethodTest2() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "\t" + i);
		}
	}

	/**
	 * 同步代码块儿:synchronized指明需要的类的实例this的对象锁(需要这个类的实例对象的对象锁)
	 *
	 * @Date 2018年8月27日 下午4:47:16
	 */
	public void synchronizedCodeBlockTest3() {
		synchronized (this) {
			for (int i = 0; i < 10; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i);
			}
		}
	}
	
	/**
	 * 同步代码块儿:synchronized指明需要的类的实例this的对象锁
	 * 测试:同步代码块儿   抢占锁的时机
	 *
	 * @Date 2018年8月27日 下午4:47:16
	 */
	public void synchronizedCodeBlockTest33() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "\t synchronized开始前" + i);
		}
		synchronized (this) {
			for (int i = 0; i < 10; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i);
			}
		}
	}

	/**
	 * 同步代码块儿:synchronized指明需要的类的实例this的对象锁
	 * 测试:同步代码块儿   释放锁的时机
	 *
	 * @Date 2018年8月27日 下午4:47:16
	 */
	public void synchronizedCodeBlockTest333() {
		synchronized (this) {
			for (int i = 0; i < 10; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i);
			}
		}
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "\t synchronized结束后" + i);
		}
	}
	
	/**
	 * 同步代码块儿:synchronized指明需要的类锁为MyThread.class(即:需要MyThread这个类的类锁)
	 *
	 * @Date 2018年8月27日 下午4:47:16
	 */
	public void synchronizedCodeBlockTest4() {
		synchronized (MyThread.class) {
			for (int i = 0; i < 10; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i);
			}
		}
	}
	
    private String string = "i have a lock!";
    // private Hashtable<String, Object> hashtable = new Hashtable<String, Object>();
	
	/**
	 * 同步代码块儿:synchronized可以指定任意 非null的 对象作为锁(不限于类、实例对象)
	 *
	 * @Date 2018年8月27日 下午4:47:16
	 */
	public void synchronizedCodeBlockTest5() {
		synchronized (string) {
			for (int i = 0; i < 10; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i);
			}
		}
	}
	
	/**
	 * 同步代码块儿:synchronized可以指定任意 非null的 对象作为锁(不限于类、实例对象)
	 *
	 * @Date 2018年8月27日 下午4:47:16
	 */
	public void synchronizedCodeBlockTest6() {
		synchronized (string) {
			for (int i = 0; i < 10; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i);
			}
		}
	}
	
	/**
	 * 普通方法
	 *
	 * @Date 2018年8月27日 下午4:47:16
	 */
	public void synchronizedNormalMethodTest7() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "\t" + i);
		}
	}

	@Override
	public void run() {
		System.out.println("重写run()");
	}
	
	
	/*
	 * 类锁  与 对象锁   互不影响
	 */
	public static void main(String[] args) {
		MyThread mt= new MyThread();
		Thread t1 = new Thread(new Runnable() {
			public void run() {
				mt.synchronizedMethodTest1();
			}
		}, "线程one");

		Thread t2 = new Thread(new Runnable() {
			public void run() {
				MyThread.synchronizedMethodTest2();
			}
		}, "线程two");

		t1.start();
		t2.start();
	}
	
//	/*
//	 * 同步代码块儿:synchronized代码块儿指定获取某个值非null的Object(不限于类、实例等)的锁
//	 */
//	public static void main(String[] args) {
//		MyThread mt= new MyThread();
//		Thread t1 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedCodeBlockTest5();
//			}
//		}, "线程one");
//
//		Thread t2 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedCodeBlockTest6();
//			}
//		}, "线程two");
//
//		t1.start();
//		t2.start();
//	}
	
//	/*
//	 * 测试同步代码块儿 ,释放锁的时机
//	 */
//	public static void main(String[] args) {
//		MyThread mt= new MyThread();
//		Thread t1 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedMethodTest1();
//			}
//		}, "线程one");
//
//		Thread t2 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedCodeBlockTest333();
//			}
//		}, "线程two");
//
//		t1.start();
//		t2.start();
//	}
	
//	/*
//	 * 测试同步代码块儿 ,抢占锁的时机
//	 */
//	public static void main(String[] args) {
//		MyThread mt= new MyThread();
//		Thread t1 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedMethodTest1();
//			}
//		}, "线程one");
//
//		Thread t2 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedCodeBlockTest33();
//			}
//		}, "线程two");
//
//		t1.start();
//		t2.start();
//	}
	
//	/*
//	 * synchronized用于同步代码块儿,但是指定对象锁---[测试对象锁]
//	 */
//	public static void main(String[] args) {
//		MyThread mt= new MyThread();
//		Thread t1 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedMethodTest1();
//			}
//		}, "线程one");
//
//		Thread t2 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedCodeBlockTest3();
//			}
//		}, "线程two");
//
//		t1.start();
//		t2.start();
//	}
	
//	/*
//	 * synchronized作用在普通方法上---[测试对象锁]
//	 */
//	public static void main(String[] args) {
//		MyThread mt= new MyThread();
//		Thread t1 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedMethodTest1();
//			}
//		}, "线程one");
//
//		Thread t2 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedMethodTest1();
//			}
//		}, "线程two");
//
//		t1.start();
//		t2.start();
//	}

//	/*
//	 * synchronized用于同步代码块儿,但是指定类锁---[测试类锁]
//	 */
//	public static void main(String[] args) {
//		MyThread mt= new MyThread();
//		Thread t1 = new Thread(new Runnable() {
//			public void run() {
//				MyThread.synchronizedMethodTest2();
//			}
//		}, "线程one");
//
//		Thread t2 = new Thread(new Runnable() {
//			public void run() {
//				mt.synchronizedCodeBlockTest4();
//			}
//		}, "线程two");
//
//		t1.start();
//		t2.start();
//	}
	
//	/*
//	 *  调用被synchronized修饰的静态方法---[测试类锁]
//	 */
//	public static void main(String[] args) {
//		Thread t1 = new Thread(new Runnable() {
//			public void run() {
//				MyThread.synchronizedMethodTest2();
//			}
//		}, "线程one");
//
//		Thread t2 = new Thread(new Runnable() {
//			public void run() {
//				MyThread.synchronizedMethodTest2();
//			}
//		}, "线程two");
//
//		t1.start();
//		t2.start();
//	}

}

 

猜你喜欢

转载自blog.csdn.net/justry_deng/article/details/82147949
今日推荐