Java并发之同步 —— synchronized 关键字

前言:    

    从java 1.0开始,java中的每一个对象都有一个内部锁。如果一个方法使用synchronized关键字声明,那么对象的锁将保护整个方法。也就是说,要调用该方法,线程必须获得对象的内部锁。

    内部的对象锁只有一个相关条件。wait方法添加一个线程到等待集中,notifyAll/notify方法解除等待线程的阻塞状态。换句话说,等价于 intrinsicCondition.await()  intrinsicCondition.signalAll()。

一、将方法声明为synchronized

public synchronized void method(){

//to do something

}


可以看到, 使用 synchronized 关键字来编写代码要简洁得多。当然,要理解这一代码,你 必须了解每一个对象有一个内部锁, 并且该锁有一个内部条件。由锁来管理那些试图进入 synchronized 方法的线程,由条件来管理那些调用 wait 的线程。

二、将静态方法声明为 synchronized 

如果调用这种方法,该方法获得相关的类对 象的内部锁。例如,如果 Bank 类有一个静态同步的方法,那么当该方法被调用时,Bank.class 对象的锁被锁住。因此,没有其他线程可以调用同一个类的这个或任何其他的同步静态方法。

三、同步阻塞

正如刚刚讨论的,每一个 Java 对象有一个锁。线程可以通过调用同步方法获得锁。还有另一种机制可以获得锁,通过进入一个同步阻塞。当线程进入如下形式的阻塞:于是它获得 Obj 的锁

synchronized (obj)

// this is the syntax for a synchronized block {

    critical section

}

例子- 使用thread2唤醒thread1

package com.java.future;


/**
 * wait()等待  notify()唤醒
 * @author Administrator
 *
 */
public class WaitAndNotify{
	private Object lock = new Object();
	
	public void method1() throws InterruptedException{
		synchronized (lock) {
			lock.wait();//当前线程获得lock对象锁后才能使用 wait() ,让当前线程挂起等待,知道被释放
			System.out.println(Thread.currentThread().getName() +" method1");
			
		}
		
	}
	
	public void method2() throws InterruptedException{
		synchronized (lock) {
			System.out.println(Thread.currentThread().getName() + " method2");
			lock.notify(); //唤醒一个正在等待这个lock对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;
		}
		
	}

	
	
	public static void main(String[] args) {
		final WaitAndNotify m = new WaitAndNotify();
		Thread t  =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m.method1();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		});
		Thread t2  =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m.method2();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		});
		t.start();
		t2.start();
	}
}

四、局限性

1.内部锁和条件存在一些局限。包括:

  • 不能中断一个正在试图获得锁的线程。
  • 试图获得锁时不能设定超时。
  • 每个锁仅有单一的条件, 可能是不够的。

2.在代码中应该使用哪一种? Lock 和 Condition 对象还是同步方法?下面是一些建议:

  • 最好既不使用 Lock/Condition 也不使用 synchronized 关键字。在许多情况下你可以使 用 java.util.concurrent 包中的一种机制,它会为你处理所有的加锁。例如,使用阻塞队列来同步完成一个共同任务的线程。还应当研究一下并行流
  • 如果 synchronized 关键字适合你的程序, 那么请尽量使用它,这样可以减少编写的代 码数量,减少出错的几率。
  • 如果特别需要 Lock/Condition 结构提供的独有特性时,才使用 Lock/Condition。

参考: Java核心技术 卷1(第9版)

猜你喜欢

转载自blog.csdn.net/zl_momomo/article/details/81201415