synchronized可以修饰非静态成员方法,修饰静态成员方法,修饰代码块,作用都是同步,但是肯定有区别的,下区分别说明:
一、synchronized修饰非静态成员方法:
在不同线程中使用同一个对象去调用该方法时,一但对象调用了方法,那么方法执行过程中,再使用同一个对象再调用该方法会被阻塞起来,直到方法执行结束!但是如果使用同一个类的不同对象去访问就起不了使用了。
例:
//Test.java
public class Test {
public synchronized void show(String name) throws InterruptedException {
for (int i = 0; i <5; i++) {
System.out.println(name + i);
Thread.sleep(1000);
}
}
}
//MyThread.java
public class MyThread extends Thread {
private String name;
private Test test;
public MyThread(String name, Test test) {
this.name = name;
this.test = test;
}
@Override
public void run() {
try {
this.test.show(this.name);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Test test = new Test();
Thread thread1 = new MyThread("小明",test);
Thread thread2 = new MyThread("小华",test);
thread1.start();
thread2.start();
}
}
运行结果为
小明0
小明1
小明2
小明3
小明4
小华0
小华1
小华2
小华3
小华4
上面的示例分析:
上面main入口方法中,两个线程对象中都传了同一个Test类的对象test,所以MyThread类中的run函数不管是thread1.start()还是thread2.start()开线程都使用
同一个对象test去调用show(Strint name)函数,所以show函数同步起使用了
如果main入口方法改为:
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test();
Thread thread1 = new MyThread("小明",test1);
Thread thread2 = new MyThread("小华",test2);
thread1.start();
thread2.start();
}
那么
thread1.start();thread2.start();起动线程后,run函数中分别使用了test1对象与test2对象去访问了show(String name)函数,同步就不会起使用了,即改成这样后
打印结果为:
小明0小华0
小明1
小华1
小明2
小华2
小明3
小华3
小明4
小华4
二、synchronized修饰静态成员方法:
只要该方法被调用,都会被同步,
例:把上面例中Test中的show方法使用static修饰,任何情况下调用show函数,函数都会被同步
public class Test {
public static synchronized void show(String name) throws InterruptedException {
for (int i = 0; i < 5; i++) {
System.out.println(name + i);
Thread.sleep(1000);
}
}
}
执行结果要么是
小明0
小明1
小明2
小明3
小明4
小华0
小华1
小华2
小华3
小华4
要么是
小华0
小华1
小华2
小华3
小华4 小明0
小明1
小明2
小明3
小明4
三、同步代码块: 可以让一个方法中部分代码被同步,当同步生效时,多个线程不能同时访问代码块中,会阻塞等待。但是也只能同步相同对象去访问有同步代码块的方法,
使用同一个类的不同对象去访问,同步不会生效。
例 1:
//Test.java
public class Test {
public void show(String name) throws InterruptedException {
synchronized (this) {
for (int i = 0; i < 5; i++) {
System.out.println(name + i);
Thread.sleep(1000);
}
}
}
}
//MyThread.java
public class MyThread extends Thread {
private String name;
private Test test;
public MyThread(String name, Test test) {
this.name = name;
this.test = test;
}
@Override
public void run() {
try {
this.test.show(this.name);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Test test = new Test();
Thread thread1 = new MyThread("小明",test);
Thread thread2 = new MyThread("小华",test);
thread1.start();
thread2.start();
}
}
同步生效: 运行结果为
小明0
小明1
小明2
小明3
小明4
小华0
小华1
小华2
小华3
小华4
如果main入口方法改为:
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test();
Thread thread1 = new MyThread("小明",test1);
Thread thread2 = new MyThread("小华",test2);
thread1.start();
thread2.start();
}
那么同步不起使用了
打印结果为:
小明0小华0
小明1
小华1
小明2
小华2
小明3
小华3
小明4
小华4