Java多线程环境下的同步机制Synchronized

一、前言

大家有没有想过一个问题,Java中的++操作是不是线程安全的呢,也就是说在多线程情况下,多个线程一起去执行++操作,得到的结果会不会是我们所预期的结果呢,可以写个demo去验证一下。

public static int count = 0;
	
public static void main(String[] args) {
	for (int j = 0; j < 10000; j++) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				add();
			}
		}).start();
	}
	try {
		Thread.sleep(200);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	System.out.println(count);
}

public static void add(){
	count++;
}
复制代码

最后的执行结果如下图: 在这里插入图片描述在这里插入图片描述 很明显,Java中的++操作,并不是线程安全的。 这就涉及到了多线程环境下,如何才能保证在操作同一个变量或者方法时保证线程安全。

二、Synchronized

什么是Synchronized?

Synchronized关键字,就是利用一个特定的对象设置一个锁(lock),在多线程并发访问的时候,只允许一个线程可以获得这个锁,并执行代码,等到代码执行完毕后,释放锁,再继续由其他线程争抢。

Synchronized的使用

我们可以稍微改造一下上面的demo,让++操作变成线程安全的。

public static int count = 0;

public static void main(String[] args) {
	for (int j = 0; j < 10000; j++) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				add();
			}
		}).start();
	}
	try {
		Thread.sleep(200);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	System.out.println(count);
}

public synchronized static void add(){
	count++;
}
复制代码

只是做个一个很小的改动,就是在add()方法中加入synchronized关键字,看一下执行结果: 在这里插入图片描述 在这里插入图片描述 多次执行得到的结果都是10000,是符合我们预期的,add()方法也变成了一个线程安全的方法。

Synchronized的使用场景

Synchronized有三种不同的使用场景,同时也对应着不同的锁对象。

1.Synchronized代码块

将上面demo的add()方法改造一下

public static void add(){
	Object o = new Object(); //锁对象
	synchronized (o){
		count++;
	}
}
复制代码

定义一个Object对象,将Object作为锁对象,只会有一个线程获得这个锁对象,执行++操作,别的线程需要等待锁对象被释放时候,争抢这个锁对象,获得锁对象的才能继续执行++

2.Synchronized方法

public synchronized void add(){
		...
		...
}
复制代码

在这个add()方法的锁对象又是什么呢,很明显,就是this当前对象,线程获得的是当先对象。

3.Synchronized静态方法

	public synchronized static void add(){
	count++;
}
复制代码

最后一种就是demo中的add()方法,这时的锁对象就是当前类的字节码对象,因为是静态方法,静态方法是属于这个类的,所以锁对象就是当前类的字节码对象。

总结

Synchronized使用在代码块中,锁对象可以是任意对象。
Synchronized使用在方法中,锁对象为当前对象this。
Synchronized使用在静态方法中,锁对象为当前类的字节码对象。
复制代码

三、常见的使用Synchronized类

Vector是线程安全的,ArrayListLinkedList是线程不安全的 Properties是线程安全的,HashSetTreeSet是不安全的 StringBuffer是线程安全的,StringBuilder是线程不安全的 HashTable是线程安全的,HashMap是线程不安全的

四、总结

Synchronized虽然可以保证多线程共享数据的数据安全,但是如果使用不当,线程长期持有锁对象,未及时得到释放,很容易造成死锁问题, 而且在性能问题上,Synchronized对性能也会有一定的影响,所以请慎用Synchronized

感谢观看,如有帮助请点个赞支持一下,谢谢。

猜你喜欢

转载自juejin.im/post/7048265996477399077