多线程3:Java内置锁与synchronized关键字

Java提供了一种内置的锁机制来支持原子性

每一个Java对象都可以用作一个实现同步的锁,称为内置锁,线程进入同步代码块之前自动获取到锁,代码块执行完成正常退出或代码块中抛出异常退出时会释放掉锁

内置锁为互斥锁,即线程A获取到锁后,线程B阻塞直到线程A释放锁,线程B才能获取到同一个锁

内置锁使用synchronized关键字实现,synchronized关键字有两种用法:

1,修饰需要进行同步的方法(所有访问状态变量的方法都必须进行同步),此时充当锁的对象为调用同步方法的对象

public class Test{
	private int count = 0;
	
	public synchronized int add(){
		count += 1;
		return count;
	}
	
	public synchronized int delete(){
		count -= 1;
		return count;
	}
}

2,同步代码块

和直接使用synchronized修饰需要同步的方法是一样的,但是锁的粒度可以更细,并且充当锁的对象不一定是this,也可以是其它对象,所以使用起来更加灵活

public class Test{
	private int count = 0;
	
	public int add(){
		synchronized(this){
			count += 1;
		}
		return count;
	}
	
	public int delete(){
		synchronized(this){
			count -= 1;
		}
		return count;
	}
}

用synchronized关键字修饰的方法可以认为是一个横跨整个方法体的同步代码块

public class Status {
	private int num = 0;
	
	public void selfIncrease(){
		num = num + 1;
		System.out.println(Thread.currentThread().getName()   
				+ "|" + num);
	}
}
public class Task implements Runnable {
	private Status status;
	
	public Task(Status status){
		this.status = status;
	}
	
	public void run() {
		synchronized (status) {
			status.selfIncrease();
		}
	}
	
	public static void main(String[] args) {
		Status status = new Status();
		Task task = new Task(status);
		Thread t1 = new Thread(task);
		Thread t2 = new Thread(task);
		Thread t3 = new Thread(task);
		Thread t4 = new Thread(task);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

运行结果为:

Thread-0|1
Thread-3|2
Thread-2|3
Thread-1|4

《多线程3:Java内置锁与synchronized关键字》

修改上面的代码,每个线程运行时创建一个新的Status对象,而不是像上面的代码,4个线程共用同一个Status对象:

public class Task implements Runnable {
	public void run() {
		Status status = new Status();
		synchronized (status) {
			status.selfIncrease();
		}
	}
	
	public static void main(String[] args) {
		Task task = new Task();
		Thread t1 = new Thread(task);
		Thread t2 = new Thread(task);
		Thread t3 = new Thread(task);
		Thread t4 = new Thread(task);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

由于充当锁的对象实例不一定是同一个对象(hashcode不同),同步失效:

Thread-0|1
Thread-1|1
Thread-3|1
Thread-2|1

《多线程3:Java内置锁与synchronized关键字》

因此同步代码块中充当锁的对象必须为同一个对象

public class Task implements Runnable {
	private Status status;
	
	public Task(Status status){
		this.status = status;
	}
	
	public void run() {
		synchronized (status) {
			System.out.println("Thread lock");
			System.out.println("Thread:" + status.getNum());
			System.out.println("Thread over");

		}
	}
	
	public static void main(String[] args) {
		Status status = new Status();
		Task task = new Task(status);
		Thread t = new Thread(task);
		t.start();
		//synchronized(status){
			System.out.println("Main");
			status.setNum(1);
			System.out.println("Main:" + status.getNum());
		//}
	}
}

运行结果为:

Main
Thread lock
Main:1
Thread:1
Thread over

从运行结果可以看出,在Thread线程锁定status对象的时候,Main线程在Thread线程释放锁对象前依然能够修改status对象的num域,说明锁没有生效

《多线程3:Java内置锁与synchronized关键字》

Main线程中没有对status对象进行同步,故在Thread线程锁定status对象的时候不需要阻塞,可以直接操作status对象,因此所有使用同步对象的地方都必须进行同步

修改方式为:Task类的main方法中,在操作status对象时进行同步(去掉代码中的注释部分)

如果锁对象为静态变量,或使用synchronized关键字修饰静态方法,则锁对象为Class对象

public class Status {
	private static int num = 0;
	
	public synchronized static void selfIncrease(){
		num = num + 1;
		System.out.println(Thread.currentThread().getName()   
				+ "|" + num);
	}
}
public class Task implements Runnable {
	
	public void run() {
		Status.selfIncrease();
	}
	
	public static void main(String[] args) throws Exception {
		Task task = new Task();
		Thread t1 = new Thread(task);
		Thread t2 = new Thread(task);
		Thread t3 = new Thread(task);
		Thread t4 = new Thread(task);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

运行结果如下:

Thread-0|1
Thread-1|2
Thread-3|3
Thread-2|4

《多线程3:Java内置锁与synchronized关键字》

相当于:

public class Status {
	private static int num = 0;
	
	public static void selfIncrease(){
		synchronized(Status.class){
			num = num + 1;
			System.out.println(Thread.currentThread().getName()   
					+ "|" + num);
		}
	}
}

或是:

public class Status {
	private static int num = 0;
	private static Object lock = new Object();
	
	public static void selfIncrease(){
		synchronized(lock){
			num = num + 1;
			System.out.println(Thread.currentThread().getName()   
					+ "|" + num);
		}
	}
}
    原文作者:java锁
    原文地址: https://blog.csdn.net/a19881029/article/details/8215775
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞