Java synchronized关键字

synchronized关键字在Java中用于线程同步

可用于

    1.修饰代码块

    2.修饰类

    3.修饰方法

1.修饰代码块
   (1)一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该代码块的线程将被阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。

示例:

package com.czlt.syncorenizedtest;

public class MyRunnerable implements Runnable {
	private int count = 0;

	@Override
	public void run() {
		synchronized (this) {
			for (int i = 0; i < 5; i++) {
				try {
					System.out.println(Thread.currentThread().getName() + ":" + (count++));
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public int getCount() {
		return count;
	}

}

测试类

package com.czlt.syncorenizedtest;

public class Test {
	public static void main(String[] args) {
		MyRunnerable mRunnerable = new MyRunnerable();
		Thread t1 = new Thread(mRunnerable, "Thread - A");
		Thread t2 = new Thread(mRunnerable, "Thread - B");
		t1.start();
		t2.start();
	}
	
}

结果:

Thread - A:0
Thread - A:1
Thread - A:2
Thread - A:3
Thread - A:4
Thread - B:5
Thread - B:6
Thread - B:7
Thread - B:8

Thread - B:9

(2)修饰代码块时,synchronized锁定的是对象

我们把测试类调整一下

package com.czlt.syncorenizedtest;

public class Test {
	public static void main(String[] args) {
//		MyRunnerable mRunnerable = new MyRunnerable();
		Thread t1 = new Thread(new MyRunnerable(), "Thread - A");
		Thread t2 = new Thread(new MyRunnerable(), "Thread - B");
		t1.start();
		t2.start();
	}
	
}

结果:

Thread - A:0
Thread - B:0
Thread - B:1
Thread - A:1
Thread - A:2
Thread - B:2
Thread - A:3
Thread - B:3
Thread - B:4
Thread - A:4

由此可见,两个线程同时执行了同步代码块。

原因: 同步代码块实际锁定的是对象,而测试类中创建线程用的是两个不同的对象,因此锁定的对象不同,两个线程可同时执行。

(3) synchronized修饰代码块时,可以指定给某个对象加锁

用法:修改(1)中的代码

package com.czlt.syncorenizedtest;

public class MyRunnerable implements Runnable {
	private int count = 0;
	Object obj1 = new Object();
	
	@Override
	public void run() {
		synchronized (obj1) {
			for (int i = 0; i < 5; i++) {
				try {
					System.out.println(Thread.currentThread().getName() + ":" + (count++));
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public int getCount() {
		return count;
	}

}


结果与(1)相同:

Thread - A:1
Thread - A:2
Thread - A:3
Thread - A:4
Thread - B:5
Thread - B:6
Thread - B:7
Thread - B:8
Thread - B:9

(4)synchronized同步代码块,指定给某个对象(假设该对象为obj1)加锁时,其他线程可访问  非synchronized修饰的代码  和  synchronized修饰的,但加锁对象非obj1的代码。

其他线程访问非synchronized修饰的代码就不给出示例了,下面给出加锁对象非obj1的代码。

package com.czlt.syncorenizedtest;

public class MyRunnerable implements Runnable {
	private int count = 0;
	Object obj1 = new Object();
	Object obj2 = new Object();
	@Override
	public void run() {
		if(Thread.currentThread().getName().equals("Thread - A")){
			synchronized (obj1) {
				for (int i = 0; i < 5; i++) {
					try {
						System.out.println(Thread.currentThread().getName() + ":" + (count++));
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		} else if(Thread.currentThread().getName().equals("Thread - B")){
			synchronized (obj2) {
				for (int i = 0; i < 5; i++) {
					try {
						System.out.println(Thread.currentThread().getName() + ":" + (count++));
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	public int getCount() {
		return count;
	}

}

测试类:

package com.czlt.syncorenizedtest;

public class Test {
	public static void main(String[] args) {
		MyRunnerable mRunnerable = new MyRunnerable();
		Thread t1 = new Thread(mRunnerable, "Thread - A");
		Thread t2 = new Thread(mRunnerable, "Thread - B");
		t1.start();
		t2.start();
	}
	
}

结果:

Thread - A:0
Thread - B:1
Thread - B:2
Thread - A:3
Thread - A:4
Thread - B:5
Thread - A:6
Thread - B:7
Thread - A:9
Thread - B:8

2. 修饰类

synchronized作用于一个类T时,是给这个类T加锁,T的所有对象用的是同一把锁。

对比1中(2)的代码,测试类相同,将synchronized修饰对象改为修饰类:

package com.czlt.syncorenizedtest;

public class MyRunnerable implements Runnable {
	private int count = 0;

	@Override
	public void run() {
		synchronized (MyRunnerable.class) {
			for (int i = 0; i < 5; i++) {
				try {
					System.out.println(Thread.currentThread().getName() + ":" + (count++));
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

	}

	public int getCount() {
		return count;
	}

}

测试类:

	public static void main(String[] args) {
//		MyRunnerable mRunnerable = new MyRunnerable();
		Thread t1 = new Thread(new MyRunnerable(), "Thread - A");
		Thread t2 = new Thread(new MyRunnerable(), "Thread - B");
		t1.start();
		t2.start();
	}

结果:

Thread - A:0
Thread - A:1
Thread - A:2
Thread - A:3
Thread - A:4
Thread - B:0
Thread - B:1
Thread - B:2
Thread - B:3
Thread - B:4

可见,修饰类的时候,虽然创建线程使用的是不同的对象,但仍然可以实现线程同步。

3. 修饰方法
(1)修饰非静态方法时,效果等同于用synchronized(this)修饰整个方法中的代码块
	public synchronized void method() {
		
	}

等同于

	public void method(){
		synchronized (this) {
			
		}
	}

(2)修饰静态方法时,效果等同于用synchronized(类名.class)修饰整个方法中的代码块
	public static synchronized void method() {
		
	}

等同于

	public static void method(){
		synchronized (MyRunnerable.class) {
			
		}
	}
(3)注意点:

    ① synchronized关键字不能继承。

    如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的

    ②构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。

    不可写成

	public synchronized MyRunnerable(){
		
	}

    但可以写成

	public  MyRunnerable(){
		synchronized (this) {
			
		}
	}

    ③不能修饰接口中的方法

    接口中,不可写成

public synchronized abstract void method1();

猜你喜欢

转载自blog.csdn.net/qq_34763699/article/details/80090256