Java中的线程同步的实现用的是锁定。
Java中的每个对象都有一个内置锁,当这个对象有同步的方法代码时,这个内置锁才会起作用。
1.非静态同步方法
(1)当进入到同步的非静态方法时,我们获得一个当前正在执行的代码的类的实例--this实例的锁,因为一个对象只有一个锁,所以当一个线程获得该锁时,其它线程就不能获得锁,即其它线程不能进入同步代码,直到当前线程释放该锁,所谓的释放锁,就是退出了这个同步方法。 只能同步方法,不能同步变量或者类 每个对象只有一个锁
(2) 多个线程可以访问类的其它非同步方法
(3) 如果线程睡眠,它依然保持已有的锁不会释放
(4)一个线程可以获得多个锁 比如它进入一个同步方法,获得当前对象的锁,而这个方法内又调用了其它对象的同步方法,因此也获得了其它对象的锁 在一个对象上调用一个同步方法,这个同步方法内调用了其它同步方法,是允许的,JVM知道当前线程获得了对象的锁
(5)可以是同步块,因为同步代码影响性能
它等价于:
这个例子有点特殊,这两段代码完全没有区别,性能也一样,但实际中代码块中可以不同步那些不需要锁定的变量
2.静态的同步方法
静态数据在类中只有一个拷贝,所以需要一个用于整个类的锁。是有这样的一个锁的,Java中装载每个类都有一个代表着该类的java.lang.class实例,使用这个实例的锁来保护该类的静态方法
可以这样写:
也可以用代码块:
这个代码块可以写成下面这个比较长的形式:
线程的阻塞:
1.使用相同实例调用同一个类中的非静态同步方法的线程将彼此阻塞,原因是它们都在这个实例上加了锁。但是如果它们使用了两个不同的实例进行调用,则它们获得两个锁,且这两个锁互不相关
2.调用静态同步方法的线程始终彼此阻塞
3.静态同步方法和非静态同步方法互不影响
4.同步块,要看看synchronized后面跟的是什么对象,在同一个对象上进行的同步线程彼此阻塞,在不同对象上则不会
何时需要同步:
局部变量不需要,因为每个线程都有一个副本,它们互不干扰
我们需要考虑的是静态字段和非静态字段
有些类被标为线程安全的类,比如StringBuffer,它只是在自己的某些方法上是线程安全的,但这不足以保证在执行过程中线程安全
Java中的每个对象都有一个内置锁,当这个对象有同步的方法代码时,这个内置锁才会起作用。
1.非静态同步方法
(1)当进入到同步的非静态方法时,我们获得一个当前正在执行的代码的类的实例--this实例的锁,因为一个对象只有一个锁,所以当一个线程获得该锁时,其它线程就不能获得锁,即其它线程不能进入同步代码,直到当前线程释放该锁,所谓的释放锁,就是退出了这个同步方法。 只能同步方法,不能同步变量或者类 每个对象只有一个锁
(2) 多个线程可以访问类的其它非同步方法
(3) 如果线程睡眠,它依然保持已有的锁不会释放
(4)一个线程可以获得多个锁 比如它进入一个同步方法,获得当前对象的锁,而这个方法内又调用了其它对象的同步方法,因此也获得了其它对象的锁 在一个对象上调用一个同步方法,这个同步方法内调用了其它同步方法,是允许的,JVM知道当前线程获得了对象的锁
(5)可以是同步块,因为同步代码影响性能
class test
{
public synchronized void doStuff()
{
System.out.println("hello");
}
}
它等价于:
class test
{
public void doStuff()
{
synchronized(this) {
System.out.println("hello");
}
}
}
这个例子有点特殊,这两段代码完全没有区别,性能也一样,但实际中代码块中可以不同步那些不需要锁定的变量
2.静态的同步方法
静态数据在类中只有一个拷贝,所以需要一个用于整个类的锁。是有这样的一个锁的,Java中装载每个类都有一个代表着该类的java.lang.class实例,使用这个实例的锁来保护该类的静态方法
可以这样写:
public static synchronized void doStuff()
{
System.out.println("hello");
}
也可以用代码块:
public static void doStuff()
{
synchronized(test.class) {//test 是这个静态方法的类名
System.out.println("hello");
}
}
这个代码块可以写成下面这个比较长的形式:
public static void doStuff()
{
Class cl=Class.forName("test");
synchronized(cl) {
System.out.println("hello");
}
}
线程的阻塞:
1.使用相同实例调用同一个类中的非静态同步方法的线程将彼此阻塞,原因是它们都在这个实例上加了锁。但是如果它们使用了两个不同的实例进行调用,则它们获得两个锁,且这两个锁互不相关
2.调用静态同步方法的线程始终彼此阻塞
3.静态同步方法和非静态同步方法互不影响
4.同步块,要看看synchronized后面跟的是什么对象,在同一个对象上进行的同步线程彼此阻塞,在不同对象上则不会
何时需要同步:
局部变量不需要,因为每个线程都有一个副本,它们互不干扰
我们需要考虑的是静态字段和非静态字段
有些类被标为线程安全的类,比如StringBuffer,它只是在自己的某些方法上是线程安全的,但这不足以保证在执行过程中线程安全