java中用synchronized实现同步处理

synchronized

Java中提供synchronized关键字实现同步处理,用synchoronized可以修饰代码块,修饰方法,来完成对 对象加锁,对类加锁的操作。synchoronized是重量级锁。意思就是当有一个线程A进入时其他想访问的线程阻塞师等待,等待该线程A执行完整个加锁区间,系统自动释放锁,并唤醒等待的其他线程竞争锁。

对象锁

synchronized修饰同步代码块 --锁new出来的实例化对象
synchoronized(this){}
代码举例子:

import sun.security.krb5.internal.Ticket;
class MyRunnable implements Runnable{
	private Integer ticket = 100;
	@Override
	public void run(){
		for(int i=0;i<100;i++){
			synchronized (this){
				if(ticket>0){
					System.out.println(Thread.currentThread().getName()+"还剩"+(ticket--)+"张票");
				}
			}
		}
	}
}
public class Test{
	public static void main(String[] args) {
		Runnable runnable = new MyRunnable();
		new Thread(runnable).start();
		new Thread(runnable).start();
		new Thread(runnable).start();
	}
}

synchronized修饰同步方法 --锁new出来的实例化对象
public synchronized void func() {}用synchronized修饰方法改写上述代码。

public synchronized void sale() {
	if (ticket > 0) {
		try {
			Thread.sleep(20);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() +"还剩" + (this.ticket--) + "张票");
	}
}

synchronized锁对象称为对象锁,这种方式只是为了防止多个线程同时执行一个对象的同步段,而对象锁顾名思义,所得是对象,而不是括号中的代码。量相当于括号中的代码是临界资源互斥访问。

全局锁

synchoronized修饰类对象
synchronized(类名.class){}
synchronized修饰类静态方法
public static synchronized void func(){}

锁任意的实例化对象

如果我们在类内锁自己的实例化对象锁this,要要是在这个类类外呢,又或者锁包为我们提供的类呢?我们一样可以锁,直接锁该类的实例化对象。Object object = new Object();c.synchronized(obj){}

总结以下

synchronized可以修饰代码块和修饰方法。在两种修饰中又可以分别锁对象,锁类对象。对象锁是重量级锁。因为线程的阻塞以及唤醒都需要操作系统由用户态切换到内核态,开销大,效率低。
而且sunchronized修饰的锁有可重入性。也就是说一但一个A线程进入代码块或者方法a获取到了锁,BC等其他线程就需要等待。他就可以随意进入锁相同对象的其他方法b\c等中。

synchronized锁同步代码块底层实现

当我们使用synchronized代码块时,要执行同步代码块首先要执行系统moniterenter操作,尝试获取moniter对象。只有当线程获取到监视器moniter对象才可以执行同步代码块,否则只能阻塞等待。同一时刻只能有一个线程获取moniter对象。在执行完代码块退出时会执行moniterexit操作。因为退出时有很多可能性,可能正常退出,可能出现异常。所以往往一个moniterenter指令对应多条moniterexit指令,以保证无论异常还是正常退出都可以正确解锁。

synchronized锁同步方法底层实现

当用 synchronized 标记方法时,你会看到字节码中方法的访问标记为ACC_SYNCHRONIZED。该标记表示在进 入该方法时,Java 虚拟机需要进行 monitorenter 操作。而在退出该方法时,不管是正常返回,还是向调用者抛异 常,Java 虚拟机均需要进行 monitorexit 操作。

这里 monitorenter 和 monitorexit 操作所对应的锁对象是隐式的。对于实例方法来说,这两个操作对应的锁对象是 this;对于静态方法来说,这两个操作对应的锁对象则是所在类的 Class 实例。

1.当执行moniterenter时,会判断moniter计数器,如果值为0,表示此时锁没有被任何线程持有,此时会将锁的持有对象设置为当前线程,并且moniter+1操作。
2.当判断moniter计数器值不为0时,判断当前锁的持有对象是不是当前请求拿锁的线程,如果相同,则寄出去再次+1,体现了可重入性。如果不相同,则等待,直到持有锁的线程释放锁。
3.当执行moniterexit时,先将moniter计时器-1操作,如果计数器剪为0,则表示锁被当前持有对象释放,所以此时已经没有线程持有锁,唤醒所有等待线程去竞争锁。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页