Java多线程之synchronized关键字全面总结2.0

为了避免出现上一张的结果,那么Java就是用了synchronized关键字。

再使用了synchronized关键字之后 一个类的实例如果想调用锁住的代码,那么这个实例必须要能够拿到对应的锁才行。而一个锁只能同时被一个实例拿到。

那么判断的根本依据就在于:实例需要拿到的是不是同一个锁! 如果是同一个锁,那么对应代码就不能同时执行,如果不是同一个锁,那么对应的代码就可以同时执行。

他有四种情况:

第一种--->代码块对象锁 :

public class Test implements Runnable {

	static Test instance = new Test();
	
	Object lock = new Object();

	public static void main(String[] args) {
		Thread thread1 = new Thread(instance);
		Thread thread2 = new Thread(instance);

		thread1.start();
		thread2.start();
		while (thread1.isAlive() || thread2.isAlive()) {
		}
		L.p("Test main 函数执行完毕");

	}

	@Override
	public void run() {
		
		synchronized (lock){
			L.p("我叫做" + Thread.currentThread().getName());
			try {
				Thread.sleep(3 * 1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			L.p(Thread.currentThread().getName() + " 执行结束");
		}
		
	
	}
}

程序输出结果应该是:

我叫做Thread-0     //  1 先打印,三秒钟后 2 3几乎同时打印 ,三秒钟后,4 5 几乎同时打印
Thread-0 执行结束
我叫做Thread-1
Thread-1 执行结束
Test main 函数执行完毕

对比来看 如果将代码做如下修改:

public class Test implements Runnable {

	static Test instance1 = new Test();
	static Test instance2 = new Test();
	
	Object lock = new Object();

	public static void main(String[] args) {
		Thread thread1 = new Thread(instance1);
		Thread thread2 = new Thread(instance2);

		thread1.start();
		thread2.start();
		while (thread1.isAlive() || thread2.isAlive()) {
		}
		L.p("Test main 函数执行完毕");

	}

	@Override
	public void run() {
		synchronized (lock){
			L.p("我叫做" + Thread.currentThread().getName());
			try {
				Thread.sleep(3 * 1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			L.p(Thread.currentThread().getName() + " 执行结束");
		}
	}
}

我们这次不是同一个实例了,变成两个不同的实例,那么程序的输出应该如下:

我叫做Thread-1   // 1 2几乎同时打印,三秒后 3 4 5几乎同时打印
我叫做Thread-0
Thread-1 执行结束
Thread-0 执行结束
Test main 函数执行完毕

为什么会出现这样的情况?根据我们判断的依据 instance1和instance2需要的是两个不同的锁,因此可以同时执行 互不影响。

在上次改变的基础上 我们再做改变  将 “Object lock = new Object();” 改成  “static Object lock = new Object();”

程序会做如下输出:

我叫做Thread-0     //  1 先打印,三秒钟后 2 3几乎同时打印 ,三秒钟后,4 5 几乎同时打印
Thread-0 执行结束
我叫做Thread-1
Thread-1 执行结束
Test main 函数执行完毕

原因还是要从判断标准出发:instance1 和 instance2 需要拿到的应该是同一个锁,这是因为 static修饰的成员被所有的对象共享。也就是说 lock对象被 instance1 和 instance2共享,instances1 和 instance2需要的都是这个lock锁,因此当instance1执行时 instance2就无法执行,必须要等到instance1执行完毕 instance2才能拿到它需要的锁,然后执行相应代码。

第二种--->普通方法锁:

public class Test implements Runnable {

	static Test instance = new Test();
	

	public static void main(String[] args) {
		Thread thread1 = new Thread(instance);
		Thread thread2 = new Thread(instance);

		thread1.start();
		thread2.start();
		while (thread1.isAlive() || thread2.isAlive()) {
		}
		L.p("Test main 函数执行完毕");

	}

	@Override
	public void run() {
		method();
	}
	
	public synchronized void method() {
		L.p("我叫做" + Thread.currentThread().getName());
		try {
			Thread.sleep(3 * 1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		L.p(Thread.currentThread().getName() + " 执行结束");
	}
}

输出如下(原因同理不再赘述):

我叫做Thread-0     //  1 先打印,三秒钟后 2 3几乎同时打印 ,三秒钟后,4 5 几乎同时打印
Thread-0 执行结束
我叫做Thread-1
Thread-1 执行结束
Test main 函数执行完毕

做修改:

public class Test implements Runnable {

	static Test instance1 = new Test();
	static Test instance2 = new Test();
	

	public static void main(String[] args) {
		Thread thread1 = new Thread(instance1);
		Thread thread2 = new Thread(instance2);

		thread1.start();
		thread2.start();
		while (thread1.isAlive() || thread2.isAlive()) {
		}
		L.p("Test main 函数执行完毕");

	}

	@Override
	public void run() {
		method();
	}
	
	public synchronized void method() {
		L.p("我叫做" + Thread.currentThread().getName());
		try {
			Thread.sleep(3 * 1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		L.p(Thread.currentThread().getName() + " 执行结束");
	}
}

输出如下(原因同理不再赘述):

我叫做Thread-1   // 1 2几乎同时打印,三秒后 3 4 5几乎同时打印
我叫做Thread-0
Thread-1 执行结束
Thread-0 执行结束
Test main 函数执行完毕

在上次修改基础上再做修改   将“public synchronized void method()”改为“public static synchronized void method()”(这其实可以划分到第三种类锁中...)

输出如下(原因同理不再赘述):

我叫做Thread-0     //  1 先打印,三秒钟后 2 3几乎同时打印 ,三秒钟后,4 5 几乎同时打印
Thread-0 执行结束
我叫做Thread-1
Thread-1 执行结束
Test main 函数执行完毕

第三种-->

public class Test implements Runnable {

	static Test instance1 = new Test();
	static Test instance2 = new Test();

	public static void main(String[] args) {
		Thread thread1 = new Thread(instance1);
		Thread thread2 = new Thread(instance2);

		thread1.start();
		thread2.start();
		while (thread1.isAlive() || thread2.isAlive()) {
		}
		L.p("Test main 函数执行完毕");

	}

	@Override
	public void run() {
		synchronized (Test.class) {
			L.p("我叫做" + Thread.currentThread().getName());
			try {
				Thread.sleep(3 * 1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			L.p(Thread.currentThread().getName() + " 执行结束");
		}
	}
}

输出如下(原因同理不再赘述):

我叫做Thread-0     //  1 先打印,三秒钟后 2 3几乎同时打印 ,三秒钟后,4 5 几乎同时打印
Thread-0 执行结束
我叫做Thread-1
Thread-1 执行结束
Test main 函数执行完毕

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值