面试题:java
答案: 面试
不能编程
不能设计模式
不能多线程
不能并发
能this
正文url
概述spa
经过分析这两个用法的分析,咱们能够理解java中锁的概念。一个是实例锁(锁在某一个实例对象上,若是该类是单例,那么该锁也具备全局锁的概念),一个是全局锁(该锁针对的是类,不管实例多少个对象,那么线程都共享该锁)。实例锁对应的就是synchronized关键字,而类锁(全局锁)对应的就是static synchronized(或者是锁在该类的class或者classloader对象上)。线程
区别
synchronized做用是对类的当前实例(对象)加锁。可使用synchronized关键字来标记一个方法或者代码块,当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便得到了该对象的锁,其余线程暂时没法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁(Java 并发编程)。
synchronized代码块【synchronized(synObject)】使用起来比synchronized方法要灵活得多。由于也许一个方法中只有一部分代码只须要同步,若是此时对整个方法用synchronized进行同步,会影响程序执行效率。而使用synchronized代码块就能够避免这个问题(同步对象或类属性),synchronized代码块能够实现只对须要同步的地方进行同步。
与Lock的区别:1. synchronized是Java语言的关键字,所以是内置特性,Lock是一个类(java.util.concurrent.locks包),经过这个类能够实现同步访问;2. synchronized不须要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完以后,系统会自动让线程释放对锁的占用。Lock则必需要用户去手动释放锁,若是没有主动释放锁,就有可能致使出现死锁现象。
每一个类有一个锁,它能够用来控制对static数据成员的并发访问。访问static synchronized方法占用的是类锁,而访问非static synchronized方法占用的是对象锁。
static synchronized控制类的全部实例(对象)的访问(相应代码块)。synchronized至关于 this.synchronized,static synchronized至关于Something.synchronized
一个日本做者-结成浩的《java多线程设计模式》有这样的一个列子:
pulbic class Something(){
public synchronized void isSyncA(){}
public synchronized void isSyncB(){}
public static synchronized void cSyncA(){}
public static synchronized void cSyncB(){}
}
那么,假若有Something类的两个实例x与y,那么下列各组方法被多线程同时访问的状况是怎样的?
a. x.isSyncA()与x.isSyncB()
b. x.isSyncA()与y.isSyncA()
c. x.cSyncA()与y.cSyncB()
d. x.isSyncA()与Something.cSyncA()
这里,很清楚的能够判断:
都是对同一个实例(x)的synchronized域访问,所以不能被同时访问。(多线程中访问x的不一样synchronized域不能同时访问)
若是在多个线程中访问x.isSyncA(),由于仍然是对同一个实例,且对同一个方法加锁,因此多个线程中也不能同时访问。(多线程中访问x的同一个synchronized域不能同时访问)
是针对不一样实例的,所以能够同时被访问(对象锁对于不一样的对象实例没有锁的约束)
由于是static synchronized,因此不一样实例之间仍然会被限制,至关于Something.isSyncA()与 Something.isSyncB()了,所以不能被同时访问。
书上的 答案是能够被同时访问的,答案理由是synchronzied的是实例方法与synchronzied的类方法因为锁定(lock)不一样的缘由。
我的分析也就是synchronized 与static synchronized 至关于两帮派,各自管各自,相互之间就无约束了,能够被同时访问。
举个例子:
public class TestSynchronized { public synchronized void test1() { int i = 5; while (i-- > 0) { System.out.println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } public static synchronized void test2() { int i = 5; while (i-- > 0) { System.out.println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } public static void main(String[] args) { final TestSynchronized myt2 = new TestSynchronized(); Thread test1 = new Thread(new Runnable() { public void run() { myt2.test1(); } }, "test1"); Thread test2 = new Thread(new Runnable() { public void run() { TestSynchronized.test2(); } }, "test2"); test1.start(); test2.start(); } }
test1 : 4 test2 : 4 test1 : 3 test2 : 3 test2 : 2 test1 : 2 test2 : 1 test1 : 1 test1 : 0 test2 : 0
上面代码synchronized同时修饰静态方法和实例方法,可是运行结果是交替进行的,这证实了类锁和对象锁是两个不同的锁,控制着不一样的区域,它们是互不干扰的。一样,线程得到对象锁的同时,也能够得到该类锁,即同时得到两个锁,这是容许的。
结论
A: synchronized static是某个类的范围,synchronized static cSync{}防止多个线程中多个实例同时访问这个 类中的synchronized static 方法。它能够对类的全部对象实例起做用。
B: synchronized 是某实例的范围,synchronized isSync(){}防止多个线程中这一个实例同时访问这个类的synchronized 方法。
其实总结起来很简单。
一个锁的是类对象,一个锁的是实例对象。
若类对象被lock,则类对象的全部同步方法全被lock;
若实例对象被lock,则该实例对象的全部同步方法全被lock。