synchronized关键字是JAVA中内置的语言级同步原语,可以通过使用这个关键字实现多线程间访问之间的同步。
synchronized关键字可以作为函数的修饰符,也可以直接在函数语句中使用,也就是平时说的同步方法和同步语句。从作用域上上来看,它可以分为作用于某个实例对象内和某个类的范围内。先看看单个对象内的用法:
1). 同步方法示例
public class Tester{
public synchronized void test(){
}
}
此时,synchronized 锁定的就是调用该同步方法对象。也就是说同一Tester对象在不同线程中调用test()方法时,必须要等前一线程执行完成之后另一线程才能执行test()方法
2). 同步语句示例
public class Tester{
public void test(){
synchronized(lock){
//代码....
}
}
}
lock可以称为对象锁,它可以是this或任何需要被锁定的对象,如果没有特别想锁定的对象,只是想实现某一代码块的同步,也可以将lock 写成任意object对象o,只要保证不同线程执行该test方法时,lock是同一个o对象即可
以上均是在某个对象的作用域内使用同步,也可以实现在类的范围内的某个方法的同步,或是让一个类的所有对象都在某个代码块的使用上同步:
public synchronized static void test(){
}
public class Tester{
public void test(){
synchronized(Tester.class){
//代码....
}
}
}
此时的对象锁是Tester类的所有对象,即假设Tester t1,Tester t2两个对象,当一个线程在执行完t1的同步语句之前,另一个线程也不能执行t2的同步语句。
synchronized的使用方法如上,下面说一下使用该关键字时的不同的情况:
(1)当多个并发线程访问同一对象的synchronized方法或语句时,一个时间内只能有一个线程可以执行该同步方法或同步语句。另一个线程必须等待当前线程执行完才能执行。
(2)当线程A访问一个对象的某一同步方法1是,其他线程必须等待A执行完1方法才能执行其他同步方法,即对该对象的其他同步方法的访问被阻塞。但是,其他线程仍然可以访问该对象任何非同步方法
线程A(为增加对比性,线程均休眠10millis)
public void run(){
t.test1();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
线程B
public void run(){
t.test2();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
主函数
public static void main(String args[]){
Tester t=new Tester();
ThreadA ta=new ThreadA(t);
ThreadB tb=new ThreadB(t);
ta.start();
tb.start();
}
未使用同步的示例
class Tester{
public void test1(){
for(int i=0;i<10;i++){
System.out.println(">>>>>>test1"+">>"+i);
}
}
public void test2(){
for(int i=0;i<10;i++){
System.out.println("test2-----"+""+i);
}
}
}
运行后结果V_1
使用同步方法
public synchronized void test1(){
for(int i=0;i<5;i++){
System.out.println(">>>>>>test1"+">>"+i);
}
}
public synchronized void test2(){
for(int i=0;i<5;i++){
System.out.println("test2-----"+""+i);
}
}
运行后结果V_2
通过运行结果对比,可知,当tester对象在线程A中调用test1()时,该对象在线程B中调用同是同步方法的test2()时被阻塞。
(3)上述情况对于sychronzied(this)或是synchronized(lock)同步语句中的其他对象锁同样使用,但要保证lock是同一个对象,否则没有同步效果。
另外,synchronized关键字无法继承。
分析完各种使用情况,最后说一下自己对线程同步的理解吧。拿前面的test()方法来说,不同线程中的同一个tester是彼此独立的,将一个tester对象看成一栋大楼,test()方法是房间,一个线程中使用tester.test()方法就好比该线程在tester大楼中开了一个新的test()房间,多个线程在并发的开房间,谁先开,使用的进度如何彼此之间并没有约束和影响。但是如果把tester对象锁定了,就像把这个大楼上了锁,一次只能允许一个线程进入(针对要使用上了锁的方法或代码块的线程而言),那么这个大楼里的所有房间(所有同步方法和同步代码块)就只有一个线程可以使用,这样,各线程对该tester对象的使用就是互斥的了,亦即有了同步的效果。