对于synchronized这个关键字,相信大家都不陌生。 可能对于一些在刚出学校的同学,在面试的时候卡在这里而让你在接下来的交锋中败下阵来,今天就带你弄懂这个关键字咯~~。
问题)当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法。
网上对于这个问题的回答,有很多是错误的。你百度的结果可能是这个错误的答案 —->不能,一个对象的synchronized方法只能由一个线程访问。而就我面试的一些公司的情况绝大多数公司就是看网上那些错误的答案。 其实正确答案要分类讨论的。
1、当一个线程进入到一个(非static 没有wait() ) synchronized方法后,其他线程是否可以访问其他非静态普通方法?
可以
package com.icoder.model;
public class SynchronizedTest {
public void normalMetod(String msg){
System.out.println(msg);
}
public synchronized void normalSyncMetod(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
} catch (Exception e) {
}
}
public static void main(String[] args) {
SynchronizedTest st=new SynchronizedTest();
Thread1 t1=st.new Thread1(st);
Thread2 t2=st.new Thread2(st);
t1.start();
t2.start();
}
class Thread1 extends Thread{
SynchronizedTest t;
public Thread1 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
normalSyncMetod("normal sync method");
}
}
class Thread2 extends Thread{
SynchronizedTest t;
public Thread2 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
normalMetod("normal method");
}
}
}
normal sync method
normal method
2、当一个线程进入到一个synchronized方法后,其他线程是否可以访问其他的非静态synchronized方法?
不能
package com.icoder.model;
public class SynchronizedTest {
public synchronized void normalSyncMetod(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
} catch (Exception e) {
}
}
public synchronized void normalSyncMetod2(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
} catch (Exception e) {
}
}
public static void main(String[] args) {
SynchronizedTest st=new SynchronizedTest();
Thread1 t1=st.new Thread1(st);
Thread2 t2=st.new Thread2(st);
t1.start();
t2.start();
}
class Thread1 extends Thread{
SynchronizedTest t;
public Thread1 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
normalSyncMetod("normal sync method");
}
}
class Thread2 extends Thread{
SynchronizedTest t;
public Thread2 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
normalSyncMetod2("normal sync method2");
}
}
}
3、当一个进程进入一个带(waite)synchronized方法后,其他进程是否可以进入其他的synchronized方法
可以
package com.icoder.model;
public class SynchronizedTest {
public synchronized void normalSyncMetod(String msg){
System.out.println(msg);
try {
wait();
Thread.sleep(*);
} catch (Exception e) {
}
}
public synchronized void normalSyncMetod2(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
notifyAll();//你可以在其他线程中唤醒处于waite的线程
} catch (Exception e) {
}
}
public static void main(String[] args) {
SynchronizedTest st=new SynchronizedTest();
Thread1 t1=st.new Thread1(st);
Thread2 t2=st.new Thread2(st);
t1.start();
t2.start();
}
class Thread1 extends Thread{
SynchronizedTest t;
public Thread1 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
normalSyncMetod("normal sync method");
}
}
class Thread2 extends Thread{
SynchronizedTest t;
public Thread2 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
normalSyncMetod2("normal sync method2");
}
}
}
4、当一个线程进入一个synchronized方法后,其他线程是否可以进入一个static synchronized方法?
可以
package com.icoder.model;
public class SynchronizedTest {
public synchronized void normalSyncMetod(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
} catch (Exception e) {
}
}
public static synchronized void staticSyncMetod2(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
} catch (Exception e) {
}
}
public static void main(String[] args) {
SynchronizedTest st=new SynchronizedTest();
Thread1 t1=st.new Thread1(st);
Thread2 t2=st.new Thread2(st);
t1.start();
t2.start();
}
class Thread1 extends Thread{
SynchronizedTest t;
public Thread1 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
normalSyncMetod("normal sync method");
}
}
class Thread2 extends Thread{
SynchronizedTest t;
public Thread2 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
staticSyncMetod2("static sync method2");
}
}
}
5、当一个线程进入静态synchronized方法后,是否可以进入一个另外一个静态synchronized方法?
不能
package com.icoder.model;
public class SynchronizedTest {
public static synchronized void normalSyncMetod(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
} catch (Exception e) {
}
}
public static synchronized void staticSyncMetod2(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
} catch (Exception e) {
}
}
public static void main(String[] args) {
SynchronizedTest st=new SynchronizedTest();
Thread1 t1=st.new Thread1(st);
Thread2 t2=st.new Thread2(st);
t2.start();
t1.start();
}
class Thread1 extends Thread{
SynchronizedTest t;
public Thread1 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
normalSyncMetod("normal sync method");
}
}
class Thread2 extends Thread{
SynchronizedTest t;
public Thread2 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
staticSyncMetod2("static sync method2");
}
}
}
6、一个线程进入静态synchronized方法后,其他线程是否可以进入普通的静态方法?
可以
package com.icoder.model;
public class SynchronizedTest {
public static void staticMetod(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
} catch (Exception e) {
}
}
public static synchronized void staticSyncMetod2(String msg){
System.out.println(msg);
try {
Thread.sleep(*);
} catch (Exception e) {
}
}
public static void main(String[] args) {
SynchronizedTest st=new SynchronizedTest();
Thread1 t1=st.new Thread1(st);
Thread2 t2=st.new Thread2(st);
t2.start();
t1.start();
}
class Thread1 extends Thread{
SynchronizedTest t;
public Thread1 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
staticMetod("static method");
}
}
class Thread2 extends Thread{
SynchronizedTest t;
public Thread2 (SynchronizedTest t){
this.t=t;
}
@Override
public void run() {
staticSyncMetod2("static sync method2");
}
}
}
----OVER!
到这里,动手敲了代码的同学都明白了吧?
我来总结下:
1、synchronized是对该类的当前实例对象的 synchronized代码区 加锁。所有被 synchronized修饰的方法全部在这个代码区里面,有个监视器,只能由然后当前对象的一个线程进入。
2、static synchronized是对该类进行加锁,换句话就是对所有实例对象的公共synchroinzed代码区加锁。所有的static synchronized修饰的方法都在这个代码区,有个监视器,只能让一个线程进入。
3、一旦在方法中有waite()释放资源锁,那么则可以进入。
synchronized与static synchronized 的区别
synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。那么static synchronized恰好就是要控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码快。实际上,在类中某方法或某代码块中有 synchronized,那么在生成一个该类实例后,改类也就有一个监视快,放置线程并发访问改实例synchronized保护快,而static synchronized则是所有该类的实例公用一个监视快了,也也就是两个的区别了,也就是synchronized相当于 this.synchronized,而static synchronized相当于Something.synchronized.
出个题目吧,还是蛮有代表性的
pulbic class Something(){
public synchronized void isSyncA(){}
public synchronized void isSyncB(){}
public static synchronized void cSyncA(){}
public static synchronized void cSyncB(){}
}
那么,加入有Something类的两个实例a与b,那么下列组方法何以被1个以上线程同时访问呢
a. x.isSyncA()与x.isSyncB()
b. x.isSyncA()与y.isSyncA()
c. x.cSyncA()与y.cSyncB()
d. x.isSyncA()与Something.cSyncA()
a 不行, b 可以,c不行, d可以
所以答案是b d