• Java 同步块


    Java同步块用来标记一个方法或一个代码块为同步的。Java同步块可以用来避免竞态。

    Java同步关键字

    在 Java 中使用 synchronized 来标记同步块。一个同步块是同步在某些对象上。同一个对象上的所有同步块只能有一个线程执行里面的代码。其他线程试图进入同步块都会被阻塞,直到同步块中的现成离开同步块。

    synchronized 可以用来标记 4 种不同的同步块:

    1. 实例方法
    2. 静态方法
    3. 实例方法中的代码块
    4. 静态代码中的代码块

    这些同步块都同步在不同的对象上。视情况去使用它。

    同步的实例方法

    public synchronized void add(int value) {
    	this.count += value;
    }
    

    一个同步实例方法是同步在拥有该方法的实例上。同步实例方法中只能有一个线程可以执行里面的方法。如果有多个实例,每个实例只能有一个线程去执行同步实例方法,也就是一个实例一个线程。

    同步静态方法

    public static synchronized void add(int value) {
    	count += value;
    }
    

    同步静态方法同步在类的类对象上。因为 JVM 中每个类只能有一个类对象。只有一个线程可以执行同一个类中的同步静态方法。
    一个类只能有一个线程,不管是执行哪一个同步静态方法。

    实例方法中的代码块

    有时候,可以不需要把整个方法同步,可以把方法的一部分同步。比如下面的代码:一个不同步的方法中包含同步的代码块

    public void add(int value) {
    	synchronized(this) {
    		this.count += value;
    	}
    }
    

    上面的示例代码使用同步块构造器来标记代码块是同步的。这个代码执行起来和同步方法一样。

    下面的代码执行效果是一样的

    public class MyClass {
    	public synchronized void log1(String msg1, String msg2) {
    		log.writeln(msg1);
    		log.writeln(msg2);
    	}
    	
    	public viod log2(String msg1, String msg2) {
    		synchronized(this) {
    			log.writeln(msg1);
    			log.writeln(msg2);
    		}
    	}
    }
    

    如果第二个同步块不是同步在this实例对象上,那么两个方法可以被线程同时执行。

    同步静态代码块

    public class MyClass {
    	public static synchronized void log1(String msg1, String msg2) {
    		log.writeln(msg1);
    		log.writeln(msg2);
    	}
    	
    	public static viod log2(String msg1, String msg2) {
    		synchronized(MyClass.class) {
    			log.writeln(msg1);
    			log.writeln(msg2);
    		}
    	}
    }
    

    这些方法都同步在类上。

    如果第二个同步块不是同步在MyClass.class这个对象上。那么这两个方法可以同时被线程访问。

    Java 同步代码例子

    public class Counter {
    	long count = 0;
    	
    	public synchronized void add(long value) {
    		this.count += value;
    	}
    }
    

    ``java
    public class CounterThread extends Thread {
    protected Counter counter = null;

    public CounterThread(Counter counter) {
    	this.counter = counter;
    }
    
    public void run() {
    	for (int i = 0; i < 10; i++) {
    		counter.add(i);
    	}
    }
    

    }

    
    ``java
    public class Example {
    	public static void main(String[] args) {
    		Counter counter = new Counter();
    		Thread threadA = new CounterThread(counter);
    		Thread threadB = new CounterThread(counter);
    		
    		threadA.start();
    		threadB.start();
    	}
    }
    

    当线程创建的时候,都传入了相同的 Counter 实例。Counter.add() 是同步实例方法。所以每次只能有一个线程可以执行该方法。另外一个线程只能等待它执行完才能去执行方法。
    如果两个线程持有的不是同一个 Counter 实例的话,就不会有这个问题。

    public class Example {
    	public static void main(String[] args) {
    		Counter counterA = new Counter();
    		Counter counterB = new Counter();
    		Thread threadA = new CounterThread(counterA);
    		Thread threadB = new CounterThread(counterB);
    		
    		threadA.start();
    		threadB.start();
    	}
    }
    

    QA

    Q:
    如果一个对象有多个方法加了synchronized,那么该对象有几把锁?

    A:
    对象锁是在一个类的对象上加的的锁,只有一把,不管有几个方法进行了同步。
    这些同步方法都共有一把锁,只要一个线程获得了这个对象锁,其他的线程就不能访问该对象的任何一个同步方法。

  • 相关阅读:
    C结构体
    读书笔记之:C语言深度剖析
    stdin、stdout、stderr
    There is an error while getting planid. No Free partitions available
    LeetCode刷题笔录Add Binary
    UVA
    谷歌google搜索打不开、谷歌gmail邮箱及相关服务无法登录的解决的方法
    C/C++中各种类型int、long、double、char表示范围(最大最小值)
    使用java进行文件编码转换
    懂,你的App生,不懂,死!
  • 原文地址:https://www.cnblogs.com/okadanana/p/5918162.html
Copyright © 2020-2023  润新知