- synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。只能同步方法,而不能同步变量和构造函数;
- Java中的每个对象都有一个锁(lock),或者叫做监视器(monitor),当一个线程访问某个对象的synchronized方法时,将该对象上锁,其他任何线程都无法再去访问该对象的synchronized方法了。直到之前的那个线程执行方法完毕后(或者是抛出了异常),才将该对象的锁释放掉,其他线程才有可能再去访问该对象synchronized方法。
- 不必同步类中所有的方法,类可以同时拥有同步和非同步方法。
- 如果两个线程要执行一个类中的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能有一个线程能够执行方法,另一个需要等待,直到锁被释放。也就是说:如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法。
- 某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
- 如果线程拥有同步和非同步方法,则非同步方法可以被多个线程自由访问而不受锁的限制。
- 线程睡眠时,它所持的任何锁都不会释放。
- 线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁。
- 同步损害并发性,应该尽可能缩小同步范围。同步不但可以同步整个方法,还可以同步方法中一部分代码块。
- 除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/},它的作用域是当前对象;在使用同步代码块时候,应该指定在哪个对象上同步,也就是说要获取哪个对象的锁。
- 调用同一个对象中非静态同步方法的线程将彼此阻塞。如果是不同对象,则每个线程有自己的对象的锁,线程间彼此互不干预。
- 调用同一个类中的静态同步方法的线程将彼此阻塞,它们都是锁定在相同的Class对象上。某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
- 当方法被同步时,它锁定对象,如果方法是静态的,它锁定类,静态同步方法和非静态同步方法将永远不会彼此阻塞,因为静态方法锁定在Class对象上,非静态方法锁定在该类的对象上。
- 对于同步代码块,要看清楚什么对象已经用于锁定(synchronized后面括号的内容)。在同一个对象上进行同步的线程将彼此阻塞,在不同对象上锁定的线程将永远不会彼此阻塞。
- synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
- Java同步仅在同一个JVM中工作,因此如果您需要在多个JVM环境中锁定某些资源,它将无法工作,您可能需要注意一些全局锁定机制。
- 我们不应该使用在常量池中维护的任何对象,例如String不应该用于同步。
public class FetchMoneyTest
{
public static void main(String[] args)
{
Bank bank = new Bank();
Thread t1 = new MoneyThread(bank);// 从银行取钱
Thread t2 = new MoneyThread(bank);// 从取款机取钱
t1.start();
t2.start();
}
}
class Bank
{
private int money = 1000;
public synchronized int getMoney(int number)
{
if (number < 0)
{ }
else if (number > money)
return -1;
{
return -2;
}
else if (money < 0)
{
return -3;
}
else
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
money -= number;
System.out.println("Left Money: " + money);
return number;
}
}
}
class MoneyThread extends Thread
{
private Bank bank;
public MoneyThread(Bank bank)
{
this.bank = bank;
}
@Override
public void run()
{
System.out.println(bank.getMoney(800));
}
}