java中的Synchronized关键字理解

  • Synchronized是java的关键字,被java语音原生支持
  • 是最基本的互斥同步手段
  • 是并发编程中的元老级角色,是并发编程的必学内容

首先引入oracle对Synchronized的解释:java

同步方法支持一种简单的策略来防止线程干扰和内存一致性错误:若是一个对象对多个线程可见,则对该对象变量的全部读取或写入都是经过同步方法完成的。编程

简单的来讲就是:在多线程同时执行一段程序时,可以保证在同一时刻最多只有一个线程执行该段程序代码,以达到保证并发安全的效果安全

首先看看在不使用并发的后果 一个i++ 10000次结果会是多少呢多线程

public class Add implements Runnable {
    static Add instance = new Add();
    
    static int i = 0;
    
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        t1.join();  //等待线程执行完再执行后面的代码
        t2.join();
        System.out.println(i);
    }
    
    @Override
    public void run() {
        for (int j = 0; j < 10000; j++) {
            i++;
        }
    }
}

复制代码

上面的栗子每次运行的结果都不同,这是由于:两个线程同时i++, 最后结果会比预计的少(i++是三个操做,读取i, i++, 将i写入内存),因此在多线程的状况下每一步执行完都有可能被打断,因此i值有可能没写进内存就执行另外一个线程的i++操做了,这种状况咱们称为线程不安全。并发


Synchronized的两个用法oracle

一、对象锁:

    a、方法锁(默认锁对象为this当前实例对象)

    b、同步代码块锁(本身指定锁对象)

二、类锁:

    概念:Java类可能有不少个对象,但只有一个Class对象,锁类时Class对象的锁(锁类只能在同一时刻被一个对象拥有)

    形式:

        a、使用关键字synchronized修饰静态的方法

        b、synchronized(*.class)代码块
复制代码

方法锁的栗子:ide

public class SimpleExample implements Runnable {
    static SimpleExample instance1 = new SimpleExample();
    
    @Override
    public void run() {
        method1();
        method2();
    }
    
    public synchronized void method1() {
    	System.out.println(Thread.currentThread().getName() + " method1 start");
    	try {
          Thread.sleep(1000);
      } catch(InterruptedException e) {
          e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + " method1 end");
    }

    public synchronized void method2() {
    	System.out.println(Thread.currentThread().getName() + " method2 start");
    	try {
          Thread.sleep(1000);
      } catch(InterruptedException e) {
          e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + " method2 end");
    }
    
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance1);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("finished");
    }
}

/** 结果: Thread-0 method1 start Thread-0 method1 end Thread-0 method2 start Thread-0 method2 end Thread-1 method1 start Thread-1 method1 end Thread-1 method2 start Thread-1 method2 end */

复制代码

对上述的结果有点不理解,(给两个方法都加上锁,当第一个线程执行完第一个方法以后,第一个方法不是会释放掉,那么第二个线程应该会有可能在第一个线程执行第二个方法以前去执行第一个方法,但结果老是第一个线程执行完再到第二个线程)本身的理解是这样的:应该两个方法上的synchronized关键字都是加在this上的,就像同步代码块那样子,若是加在同一个对象上,那么线程会依次执行。ps:但愿高手能指教...this


使用关键字synchronized修饰静态的方法,这样能够在一些全局方法上作到同步spa

public class SimpleExample implements Runnable {
    static SimpleExample instance1 = new SimpleExample();
    static SimpleExample instance2 = new SimpleExample();
    
    @Override
    public void run() {
        method1();
    }
    
    public static synchronized void method1() { //若是把static去掉,线程就不会是同步的
    	System.out.println(Thread.currentThread().getName() + " method1 start");
    	try {
          Thread.sleep(500);
      } catch(InterruptedException e) {
          e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + " method1 end");
    }
    
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance2);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("finished");
    }
}

/** 结果: Thread-0 method1 start Thread-0 method1 end Thread-1 method1 start Thread-1 method1 end */
复制代码

总结

  • 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待
  • 每一个实例都对应有本身的一把锁,不一样实例之间互不影响;例外:锁对象是×。class以及synchronied修饰的是static方法的时候,全部对象共用一把锁
  • 不管是方法正常执行完毕或者方法抛出异常,都会释放锁
相关文章
相关标签/搜索