zoukankan      html  css  js  c++  java
  • synchronized关键字详解

    synchronized(源于马士兵教育课程)

    1.synchronized关键字

    public class T {
    	private int count = 10;
    	private Object o = new Object();
    	public void m() {
    		synchronized(o) { //任何线程要执行下面的代码,必须先拿到o的锁
    			count--;
    			System.out.println(Thread.currentThread().getName() + " count = " + count);
    		}
    	}
    }
    
    public class T {
    	private int count = 10;
    	public void m() {
    		synchronized(this) { //任何线程要执行下面的代码,必须先拿到this的锁
    			count--;
    			System.out.println(Thread.currentThread().getName() + " count = " + count);
    		}
    	}
    }
    
    public class T {
    	private int count = 10;
    	public synchronized void m() { //等同于在方法的代码执行时要synchronized(this)
    		count--;
    		System.out.println(Thread.currentThread().getName() + " count = " + count);
    	}
    }
    
    public class T {
    	private static int count = 10;
    	public synchronized static void m() { //这里等同于synchronized(FineCoarseLock.class)
    		count--;
    		System.out.println(Thread.currentThread().getName() + " count = " + count);
    	}
    	public static void mm() {
    		synchronized(T.class) { //考虑一下这里写synchronized(this)是否可以?
    			count --;
    		}
    	}
    }
    
    • synchronized对象锁
    • synchronized类锁

    2.同步和非同步方法是否可以同时调用?

    package com.mashibing.juc.c_007;
    public class T {
    	public synchronized void m1() { 
    		System.out.println(Thread.currentThread().getName() + " m1 start...");
    		try {
    			Thread.sleep(10000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println(Thread.currentThread().getName() + " m1 end");
    	}
    	public void m2() {
    		try {
    			Thread.sleep(5000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println(Thread.currentThread().getName() + " m2 ");
    	}
    	public static void main(String[] args) {
    		T t = new T();
    		new Thread(t::m1, "t1").start();
    		new Thread(t::m2, "t2").start();
    	}
    }
    
    • 输出:
    t1 m1 start...
    t2 m2 
    t1 m1 end
    
    • 可以同时调用

    3.synchronized锁的可重入性

    /**
     * 一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁.
     * 也就是说synchronized获得的锁是可重入的
     * @author mashibing
     */
    package com.mashibing.juc.c_009;
    import java.util.concurrent.TimeUnit;
    public class T {
    	synchronized void m1() {
    		System.out.println("m1 start");
    		try {
    			TimeUnit.SECONDS.sleep(1);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		m2();
    		System.out.println("m1 end");
    	}
    	synchronized void m2() {
    		try {
    			TimeUnit.SECONDS.sleep(2);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("m2");
    	}
    	public static void main(String[] args) {
    		new T().m1();
    	}
    }
    
    /**
     * 一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁.
     * 也就是说synchronized获得的锁是可重入的
     * 这里是继承中有可能发生的情形,子类调用父类的同步方法
     * @author mashibing
     */
    package com.mashibing.juc.c_010;
    import java.util.concurrent.TimeUnit;
    public class T {
    	synchronized void m() {
    		System.out.println("m start");
    		try {
    			TimeUnit.SECONDS.sleep(1);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("m end");
    	}
    	public static void main(String[] args) {
    		new TT().m();
    	}
    }
    class TT extends T {
    	@Override
    	synchronized void m() {
    		System.out.println("child m start");
    		super.m();
    		System.out.println("child m end");
    	}
    }
    
    • 若synchronized不可重入,则上述代码会发生死锁

    4.synchronized与异常

    /**
     * 程序在执行过程中,如果出现异常,默认情况锁会被释放
     * 所以,在并发处理的过程中,有异常要多加小心,不然可能会发生不一致的情况。
     * 比如,在一个web app处理过程中,多个servlet线程共同访问同一个资源,这时如果异常处理不合适,
     * 在第一个线程中抛出异常,其他线程就会进入同步代码区,有可能会访问到异常产生时的数据。
     * 因此要非常小心的处理同步业务逻辑中的异常
     * @author mashibing
     */
    package com.mashibing.juc.c_011;
    import java.util.concurrent.TimeUnit;
    public class T {
    	int count = 0;
    	synchronized void m() {
    		System.out.println(Thread.currentThread().getName() + " start");
    		while(true) {
    			count ++;
    			System.out.println(Thread.currentThread().getName() + " count = " + count);
    			try {
    				TimeUnit.SECONDS.sleep(1);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			if(count == 5) {
    				int i = 1/0; //此处抛出异常,锁将被释放,要想不被释放,可以在这里进行catch,然后让循环继续
    				System.out.println(i);
    			}
    		}
    	}
    	public static void main(String[] args) {
    		T t = new T();
    		Runnable r = new Runnable() {
    			@Override
    			public void run() {
    				t.m();
    			}
    		};
    		new Thread(r, "t1").start();
    		try {
    			TimeUnit.SECONDS.sleep(3);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		new Thread(r, "t2").start();
    	}
    }
    
    • 出现异常,默认情况锁会被释放

    5.synchronized锁住的对象不可是string,Integer,Long等常量对象

    6.synchronized的底层实现

    synchronized的底层实现
    JDK早期的 重量级 - OS
    后来的改进
    锁升级的概念:
    sync (Object)
    markword 记录这个线程ID (偏向锁)
    如果线程争用:升级为 自旋锁
    10次以后,
    升级为重量级锁 - OS
    偏向锁->自旋锁->重量级锁
    前两者占用CPU,重量级锁进入等待队列,不占用CPU
    执行时间短(加锁代码),线程数少,用自旋
    执行时间长,线程数多,用系统锁

  • 相关阅读:
    使用Fiddle修改请求数据
    Fiddle抓包应用概述
    s = -1 #作用域之外的数字是不会改的
    python list.reverse() 方法 不可以 ss = li.reverse() ,这个列表翻转方法没有返回值, ss=None
    python 两个tuple元组之间连接判断是否有一个为空, and 和 & ,只能用and 不能用&
    http 协议最大url是不限制的,但实际上不会很长,有服务器的限制
    这个居然也可以python >>>geturl()["a"]
    python的字典可以这样子 print(dic["ab"+cd]) 震惊!!!
    mysql 远程 死活连不上 阿里云搞得个什么鬼
    txt默认的是个什么格式,anex,什么的,另存为utf-8或者unicode中文就不乱了
  • 原文地址:https://www.cnblogs.com/fjf3997/p/13217556.html
Copyright © 2011-2022 走看看