synchronized关键字是控制java中线程同步的,能够分为synchronized块和synchronized方法两种状况。弄懂具体功能及它们的异同仍是颇有必要的。java
一、同步方法ide
新建的测试类:测试
//the synchronized functions are in this class class Executer { public synchronized void execute1() { for (int i = 0; i < 3; ++i) { System.out.println(i); } } public synchronized void execute2() { for (int i = 0; i < 3; ++i) { System.out.println(i); } } } //thread1, it will invoke the function "execute1()" in Executer class Thread1 extends Thread { private Executer executer; public Thread1(Executer executer) { this.executer = executer; } @Override public void run() { executer.execute1();/ } } //thread2, it will invoke the function "execute2()" in Executer class Thread2 extends Thread { private Executer executer; public Thread2(Executer executer) { this.executer = executer; } @Override public void run() { executer.execute2(); } }
1.一、当两个线程访问同一个对象的同一个同步方法:this
main方法所在类:spa
public class SyncTest { public static void main(String[] args) { Executer executer = new Executer();//initiate only one instance Thread t1 = new Thread1(executer); Thread t2 = new Thread1(executer);//t1 and t2 are both instance of Thread1, and they will both invoke the function "execute1()". t1.start(); t2.start(); } }
输出结果显然是线程
0 1 2 0 1 2
t1先执行execute1()方法,给其上锁。访问完毕后解锁,再由t2去访问。而若是execute1()不加synchronized方法的话,输出将会是00 11 22,也就是t1, t2两个线程同时访问execute1()方法。如今咱们须要知道这个“锁”是上在哪里的。code
1.二、当两个线程访问同一个对象的不一样同步方法:orm
main方法所在类:对象
public class SyncTest2 { public static void main(String[] args) { Executer executer = new Executer();//initiate only one instance Thread t1 = new Thread1(executer); Thread t2 = new Thread2(executer);//t1 will invoke the function "execute1()". And t2 will invoke "execute2()". t1.start(); t2.start(); } }
结果执行输出为:
同步
0 1 2 0 1 2
跟上例的结果同样。而咱们这里两个线程访问的明明是两个不一样的方法。这说明当有线程访问同步方法(synchronized)时,会给对象上锁,而不是方法。上锁期间,其余线程不能访问该对象的任何同步方法。直到此线程结束或者抛异常,才会把锁释放。再来进一步研究锁的级别。
1.三、静态方法的同步
将测试类做以下修改(将Executer中的方法改成静态,两个Thread类不变):
class Executer { public synchronized static void execute1() {//static synchronized for (int i = 0; i < 3; ++i) { System.out.println(i);//print i. } } public synchronized static void execute2() {//static synchronized for (int i = 0; i < 3; ++i) { System.out.println(i);//print i. } } }
而后在main方法中如是输入:
public class SyncTest2 { public static void main(String[] args) { Executer executer1 = new Executer(); Executer executer2 = new Executer();//initiate two instances Thread t1 = new Thread1(executer1);//invoke execute1() Thread t2 = new Thread2(executer2);//invoke execute2() t1.start(); t2.start(); } }
输出结果:
0 1 2 0 1 2
依然同步。这里咱们建立了两个对象实例,按理说不一样线程访问各自对象的同步方法的时候,两个线程间应该互不影响。然而,结果却说明它们之间会有制约关系。问题就出在static关键字。被static修饰的方法为类方法,而非是对象层面的。当方法同时被static synchronized关键字修饰,线程访问此方法时会给这个类上锁,而不单单是对象。期间其余线程没法访问这个类的全部静态同步方法。
2.同步块
其实也能够将Executer类中的方法以下写:
class Executer { private Object object = new Object(); public void execute1() { synchronized (object) { for (int i = 0; i < 3; ++i) { System.out.println(i); } } } public void execute2() { synchronized (object) { for (int i = 0; i < 3; ++i) { System.out.println(i); } } } }
实现的效果跟以前的1.2例同样。原理就是对object对象加上锁,同时只能有一个线程能够访问该方法。
而后如今有这样一个问题:
public class SyncTest extends Thread { private static String str = ""; private String type = ""; private static void method(String s) { synchronized (str) { /************ //str = s; ************/ System.out.println(s); while(true){ } } } public void method1() { method("method1"); } public static void staticMethod1() { method("staticMethod1"); } public void run() { if(type.equals("static")) { staticMethod1(); } else{ method1(); } } public SyncTest(String type) { this.type = type; } public static void main(String[] args) { SyncTest1 test1 = new SyncTest1("nonstatic"); SyncTest1 test2 = new SyncTest1("static"); test1.start(); test2.start(); } }
问注释那一行加与不加什么区别?
如下是解开注释的结果:
method1 staticMethod1
而后陷入while无限循环。
如下是注释掉的结果:
method1
也是陷入了while无限循环。
其实产生这个差异的主要缘由是synchronized块里的object改变了。注释那行是修改了此object。若是加上这一行,会致使从新产生一个String对象,此方法快的同步性将被破坏,因而出现了两个方法同时访问这个“同步块”的状况。
顺便说一下,同步块里的参数只能是对象(object),不能是基本类型的数据(如int,byte)。
因为同步块的控制比较细粒度,并且能够传this关键字进去(至关于当前对象的一个synchronized修饰的方法),因此使用上可能会更普遍一点吧。