synchronized关键字

1. 基本概念:

在Java中当多线程访问一个方法或者代码块时,可能造成因为抢夺资源而造成进程死锁
使用synchronized关键字可以防止进程死锁

2. 主要用法

可以修饰在方法上

比如
 public void synchronized void method(){
 			//代码块
  }

可以修饰在对象上

  比如
   synchronized(某个对象){
   		//代码块
    } 

可以修饰在类上

  比如
   synchronized(类名.class){
   //代码块
   } 

3. 修饰在方法上

 public class SynchronizedTest1 {
	public synchronized void methodA(){
		try {
			for (int i = 0; i < 5; i++) {
				System.out.println("methodA()-"+i);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	public void methodB(){
		try {
			for (int i = 0; i < 5; i++) {
				System.out.println("methodB()-"+i);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		SynchronizedTest1 test = new SynchronizedTest1();
		
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				test.methodA();				
			}
		});
		t1.start();
		
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				test.methodB();
			}
		});
		t2.start();
	}
}

结果显示:作用在同一个实例对象一个线程调用synchronized方法修饰的方法,另一个线程调用没有被
synchronized修饰的方法,是异步的,并行执行
在这里插入图片描述

public class SynchronizedTest1_1 {
	public synchronized void methodA(){
		try {
			for (int i = 0; i < 5; i++) {
				System.out.println("methodA()-"+i);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	public synchronized void methodB(){
		try {
			for (int i = 0; i < 5; i++) {
				System.out.println("methodB()-"+i);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	
	public static void main(String[] args) {
		SynchronizedTest1_1 test1 = new SynchronizedTest1_1();

		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodA();				
			}
		});
		t1.start();
		
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodB();
			}
		});
		t2.start();
	}
}

结果显示:作用在同一个实例对象,两个线程都调用synchronized修饰的方法,是同步的,串行执行
在这里插入图片描述
总结:
  1.当一类中的方法有被synchronized修饰时,一个线程被调用了被synchronized修饰的方法,那么其他线程就不能调用synchronized修饰的方法,原因:一个线程获得了对象的锁之后,其他线程就不能再获取这个对象的锁,只能等获取到锁的线程执行完后,才能够获取到对象的锁
  2.当一类中的方法有被synchronized修饰时,一个线程被调用了被synchronized修饰的方法,但是其他线程可以调用没有被synchronized修饰的方法,原因:调用没有被synchronized修饰的方法,就不需要获取当前对象的锁,可以直接调用方法
  3.如果实例化两个上面类的对象,那么test1和test2,即使同时调用methodA()方法,也是并行执行,是同步的,因为所调用的对象不是一个对象

4. 修饰在对象上

public class SynchronizedTest2 {
	public void methodA(){
		//同步代码块
		synchronized(this){
			try {
				for (int i = 0; i < 5; i++) {
					System.out.println("methodA()-"+i);
					Thread.sleep(1000);
				}
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
		
	}
	public void methodB(){
		try {
			for (int i = 0; i < 5; i++) {
				System.out.println("methodB()-"+i);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		SynchronizedTest2 test1 = new SynchronizedTest2();
		
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodA();				
			}
		});
		t1.start();
		
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodB();
			}
		});
		t2.start();
	}
}

结果显示:作用在同一个实例对象上,一个线程调用synchronized代码块,另一个线程可以调用非
synchronized代码块,是异步的,并行执行
在这里插入图片描述

public class SynchronizedTest2_1 {
	public void methodA(){
		//同步代码块
		synchronized(this){
			try {
				for (int i = 0; i < 5; i++) {
					System.out.println("methodA()-"+i);
					Thread.sleep(1000);
				}
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
	}
	public void methodB(){
		synchronized(this){
			try {
				for (int i = 0; i < 5; i++) {
					System.out.println("methodB()-"+i);
					Thread.sleep(1000);
				}
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		SynchronizedTest2_1 test1 = new SynchronizedTest2_1();
		
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodA();				
			}
		});
		t1.start();
		
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodB();
			}
		});
		t2.start();
	}
}

结果显示:作用在同一个实例对象,两个线程都调用synchronized修饰的代码块,是同步的,串行执行
在这里插入图片描述
总结:
  修饰在代码块上的synchronized可以使代码实用性更强,达到只同步方法中的部分代码,而不是同步所有的代码

5. 同时修饰在方法和对象上

public class SynchronizedTest3 {
	//给方法加同步
	public synchronized void methodA(){
		try {
			for (int i = 0; i < 5; i++) {
				System.out.println("methodA()-"+i);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
	}
	//给代码块加同步
	public void methodB(){
		synchronized(this){
			try {
				for (int i = 0; i < 5; i++) {
					System.out.println("methodB()-"+i);
					Thread.sleep(1000);
				}
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		SynchronizedTest3 test1 = new SynchronizedTest3();
		
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodA();				
			}
		});
		t1.start();
		
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodB();
			}
		});
		t2.start();
	}
}

结果显示:作用在同一个实例对象上,synchronized和synchronized(this)二者没有区别,都作用在this对象上, 给this对象添加锁,所以会同步,串行执行
在这里插入图片描述
总结:
  1.synchronized和synchronized(this)二者没有区别,都作用在this对象上,当都需要调用对象的锁的时候,就要等待前者执行完后,才能获取对象的锁
  2. 如果把methodB()方法中的this换成别的对象,那么调用此方法所需要的对象的锁就不是当前test1对象的锁,而是该方法所修饰对象的锁,那么线程t1和t2就是同步的,并行执行

6. 修饰在类上:

public class SynchronizedTest4 {
	public synchronized static void methodA(){
		try {
			for (int i = 0; i < 5; i++) {
				System.out.println("methodA()-"+i);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
	}
	public void methodB(){
		synchronized(SynchronizedTest4.class){
			try {
				for (int i = 0; i < 5; i++) {
					System.out.println("methodB()-"+i);
					Thread.sleep(1000);
				}
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		SynchronizedTest4 test1 = new SynchronizedTest4();
		
		
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodA();				
			}
		});
		t1.start();
		
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				test1.methodB();
			}
		});
		t2.start();
	}
}

结果显示:修饰在类上所以是同一对象的锁,所以是同步的串行执行
在这里插入图片描述
总结:
  1.static synchronized 和 synchronized(类名.class)都是作用在同一个类锁上,所以会同步
  2.如果把synchronized(类名.class)中的类名换成Object(指的是与static synchronized修饰的不同的类),那么t1和t2就是异步的可以并行执行

7. 总结:

1.方法上只有synchronized关键字锁的是对象,方法上有static synchronized两个关键字修饰锁的是类
2.在分析synchronized关键字时要注意不是修饰的方法锁的就是方法,可能时对象或者类
3.有多个synchronized关键字的方法,执行时需要等待对象的锁,先占有锁的线程先执行,其他线程要等待对象的锁,拿到锁之后才能执行
4.注意不带synchronized关键字的方法,线程调用的时候不需要等待对象的锁可以直接执行

  • 个人感悟:

通过今天的学习多少对synchronized关键字有了一点自己的了解,一面的一些结论是自己撰写的,可能措辞有些不恰当,大家可以提出来,我会尽快改正,另外,如果大家觉得我写的有问题,也可以和我来探讨,走向java大佬的路还很,漫长呀!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值