IT教程 ·

Java synchronized 关键字详解

基于 React 实现一个 Transition 过渡动画组件

Java synchronized 关键字详解

前置妙技点

  • 历程和线程的观点
  • 线程建立体式格局
  • 线程的状况状况转换
  • 线程平安的观点

synchronized 关键字的几种用法

  1. 润饰非静态成员要领
    synchronized public void sync(){
    
    }
  2. 润饰静态成员要领
    synchronized public static void sync(){
    
    }
  3. 类锁代码块
    synchronized (类.class){
    
    }
  4. 对象锁代码块
    synchronized (this|对象){
    
    }

synchronized 润饰非静态要领时能够看作是锁 this 对象,润饰静态要领时能够看作是锁要领地点的类。

synchronized 关键字的基础机制

各个线程想要接见被 synchronized 润饰的代码块,就要获得 synchronized 声明的锁。假如两个线程的目的是统一个锁,就会涌现壅塞的征象,所以两个线程不能同时接见统一个锁下的代码,保证了多线程在实行时终究效果不会失足。这与同享变量是不是为静态无关。

几个例子

对象锁

public class ThreadDemo extends Thread {
    @Override
    public synchronized void run() {
        for (int i = 0; i < 10000; i++) {
            Main.i++;
        }
        System.out.println("实行完成");
    }
}

直接将继续的 run() 要领标记为 synchronized ,作用是对 Main 类中的 i 变量做 10000 次累加操纵。

public class Main {
    static int i = 0;

    public static void main(String[] args) throws InterruptedException {
        ThreadDemo threadDemo=new ThreadDemo();
        Thread t1 = new Thread(threadDemo);
        Thread t2 = new Thread(threadDemo);
        Thread t3 = new Thread(threadDemo);
        Thread t4 = new Thread(threadDemo);

        t1.start();
        t2.start();
        t3.start();
        t4.start();

        t1.join();
        t2.join();
        t3.join();
        t4.join();
        System.out.println(i);
    }
}
//输出效果:
//实行完成
//实行完成
//实行完成
//实行完成
//40000

能够看到当4个线程悉数实行终了以后,变量 i 胜利的累加了 40000 次,没有涌现丧失操纵的状况。

假如我们将 main() 要领修正以下:

public static void main(String[] args) throws InterruptedException {
    Thread t1 = new ThreadDemo();
    Thread t2 = new ThreadDemo();
    Thread t3 = new ThreadDemo();
    Thread t4 = new ThreadDemo();

    t1.start();
    t2.start();
    t3.start();
    t4.start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    System.out.println(i);
}
//输出效果:
//实行完成
//实行完成
//实行完成
//实行完成
//27579

能够看到丧失了不少的累加操纵。视察前后两个 main() 要领建立线程的体式格局能够发明,前面的 main() 要领是运用了统一个对象来建立了4个差别的线程,然后一个 main() 要领运用了4个差别的 ThreadDemo 对象建立了4个线程。我们用 synchronized 润饰的是一个非静态成员函数,相当于对该要领建立了 this 的对象锁。在第一个 main() 要领中运用统一个对象来建立 4 个差别线程就会让 4 个线程争取统一个对象锁,如许,在统一时间内,仅能有一个线程能接见 synchronized 润饰的要领。而在第二种 main() 要领中,4 个线程各自对应一个对象锁,4 个线程之间没有合作关联,对象锁天然没法见效。

类锁

public class ThreadDemo extends Thread {
    @Override
    public void run() {
        synchronized (ThreadDemo.class) {
            for (int i = 0; i < 10000; i++) {
                Main.i++;
            }
            System.out.println("实行完成");
        }
    }
}

将润饰要领的 synchronized 改成对 ThreadDemo.class 上锁的代码块

public class ThreadDemo2 extends Thread {
    @Override
    public void run() {
        synchronized (ThreadDemo2.class) {
            for (int i = 0; i < 10000; i++) {
                Main.i++;
            }
            System.out.println("实行完成");
        }
    }
}

再建立一个雷同的类命名为 ThreadDemo2 ,与 ThreadDemo 差别的是,ThreadDemo2 中,synchronized 对 ThreadDemo2.class 上锁。

public static void main(String[] args) throws InterruptedException {
    Thread t1 = new ThreadDemo();
    Thread t2 = new ThreadDemo();
    Thread t3 = new ThreadDemo2();
    Thread t4 = new ThreadDemo2();

    t1.start();
    t2.start();
    t3.start();
    t4.start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    System.out.println(i);
}
//输出效果:
//实行完成
//实行完成
//实行完成
//实行完成
//33054

4 个线程离别由 ThreadDemo 和 ThreadDemo2 来建立,明显获得的效果与预期的 40000 不符。假如我们将 ThreadDemo2 中的 synchronized 改成对 ThreadDemo.class 上锁:

public class ThreadDemo2 extends Thread {
    @Override
    public void run() {
        synchronized (ThreadDemo.class) {
            for (int i = 0; i < 10000; i++) {
                Main.i++;
            }
            System.out.println("实行完成");
        }
    }
}
//输出效果:
//实行完成
//实行完成
//实行完成
//实行完成
//40000

能够看到,虽然是声明在两个差别的类中的 synchronized 代码块,然则因为都是对 ThreadDemo.class 上锁,所以 4 个线程之间照样建立了合作关联,同时只能有一个线程接见被 synchronized 润饰的代码。

总结

所以 synchronized 关键字的实质是限定线程接见一段代码,而限定的前提就是,在所有被加上雷同锁的代码上,统一时间,只能有一个线程在运转。这与你要修正什么样的同享变量无关。在我刚接触到的时刻认为类锁和对象锁是离别针对静态同享变量和非静态同享变量的,但现实上锁的是要实行的代码块,而不是代码块将要接见的同享变量。

Nginx之常用基本配置(一)

参与评论