zoukankan      html  css  js  c++  java
  • 线程同步 synchronized

    1、了解 synchronized

    在Java中,每一个对象都拥有一个锁标记(monitor),也称为监视器,多线程同时访问某个对象时,线程只有获取了该对象的锁才能访问,这个锁可通过为方法添加关键字 synchronized 来获得,来保证同一对象在同一

    时间只有同一线程在访问,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。

    2、synchronized的特点

    (1)对于synchronized方法或者synchronized代码块,当出现异常时,JVM会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象

    (2)使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

    (3)通过synchronized无法知道有没有成功获取锁。

    3、三种使用方式

    (1)修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁

    public synchronized void increase(){
      i++;
    }

    对于当前类的对象加锁,不同对象有不同的锁,针对同一线程访问的加锁;若是两个对象,则两个对象获取不同的锁,两个线程可以同时进入该方法,以上代码的加锁就会出现线程不安全

    (2)修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁

    public static synchronized void increase(){
       i++;
    }

    作用于静态方法时,其锁就是当前类的class对象锁。由于静态成员不专属于任何一个实例对象,是类成员,即所有该类的对象获取到的都是同一把锁,因此通过class对象锁可以控制静态 成员的并发操作。

    (3)修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

    修饰代码块有以下三种情况:

      1.对给定对象加锁

    public void run() {
            //省略其他耗时操作....
            //使用同步代码块对变量i进行同步操作,锁对象为obj
            synchronized(obj){
                for(int j=0;j<1000000;j++){
                        i++;
                  }
            }
        }

    该类的不同对象获取到obj的锁是同一把锁,两个线程不能进入该方法,保证线程安全

      2.对当前实例对象 this 加锁

    //this,当前实例对象锁
    synchronized(this){
        for(int j=0;j<1000000;j++){
            i++;
        }
    }

    此情况和修饰实例方法的情况相同,有两个线程对象时,会出现线程不安全

      3.对class对象加锁

    //class对象锁
    synchronized(AccountingSync.class){
        for(int j=0;j<1000000;j++){
            i++;
        }
    }

    该类的不同对象获取到的class对象锁是同一把锁,两个线程不能进入该方法,保证线程安全

    4、使用代码

    public class SyncTest extends Thread {
        private int i=0;
        private String str="obj";
    
        public void run(){
            synchronized (str){
                while (i<5){
                    i++;
                    System.out.println(Thread.currentThread().getName()+":"+i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            SyncTest t1=new SyncTest();
            SyncTest t2=new SyncTest();
            t1.start();
            t2.start();
        }
    }

    结果

    Thread-0:1
    Thread-0:2
    Thread-0:3
    Thread-0:4
    Thread-0:5
    Thread-1:1
    Thread-1:2
    Thread-1:3
    Thread-1:4
    Thread-1:5

    线程-1是等线程-0执行完后才执行的

  • 相关阅读:
    20200226 Java IO流——廖雪峰
    20200225 Java 多线程(2)-廖雪峰
    20200225 Java 多线程(1)-廖雪峰
    20200224 尚硅谷ElasticSearch【归档】
    20200224 一 概述
    20200222 尚硅谷Dubbo【归档】
    20200222 四、dubbo原理
    Improved robustness of reinforcement learning policies upon conversion to spiking neuronal network platforms applied to Atari Breakout game
    Reinforcement learning in populations of spiking neurons
    Solving the Distal Reward Problem through Linkage of STDP and Dopamine Signaling
  • 原文地址:https://www.cnblogs.com/yjh1995/p/11714190.html
Copyright © 2011-2022 走看看