简述
synchronized关键字可以使得被修饰的对象(此对象非实例化对象)在同一时间只能被同一个线程访问。
是一个非公平锁,即谁先抢到是谁的。
结论
修饰的对象 | 争夺的对象 |
---|---|
非静态方法 | 调用此方法的对象 |
静态方法 | 调用此方法的对象的类 |
代码块后的括号内为类的class | 调用此代码块的对象的类 |
代码块后的括号内为this | 调用此代码块的对象 |
调试:
一、修饰方法
我们启动两个线程去分别执行同一个类的两个对象中的f1方法,观察现象:
1、当synchronized修饰非静态方法时,控制台将每0.5秒输出两次线程名。
2、当synchronized修饰静态方法时,控制台将每0.5秒输出一次线程名。
也就是说
- 修饰非静态方法:争夺的是调用此方法的对象。
- 修饰静态方法:争夺的是调用此方法的对象的类(静态的属于类)。
class syn_Test {
public synchronized static void f1() throws InterruptedException {
System.out.println(Thread.currentThread().getName());
Thread.sleep(500);
}
}
class ceshi {
public static void main(String[] argv) throws Exception {
syn_Test t1 = new syn_Test();
syn_Test t2 = new syn_Test();
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
t1.f1();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
t2.f1();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
二、修饰代码块
我们启动四个线程去分别执行同一个类的两个对象中的f1、f2方法,观察现象:
很抱歉让您做了一次阅读理解
1、当synchronized修饰的代码块内为this时,控制台将每0.5秒输出两次线程名。
2、当synchronized修饰的代码块内为类的class对象时控制台将每0.5秒输出一次线程名。
也就是说
- 括号内为this时争夺的是调用此方法的对象
- 括号内为类的class对象时争夺的是调用此方法的对象的类。
class syn_Test {
public void f1() throws InterruptedException {
synchronized (testTiaoJianSuo.class) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(500);
}
}
public void f2() throws InterruptedException {
synchronized (this) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(500);
}
}
}
class ceshi {
public static void main(String[] argv) throws Exception {
// 实例化两对象
syn_Test t1 = new syn_Test();
syn_Test t2 = new syn_Test();
// 启动四个进程分别执行两对象的四个方法
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
t1.f1();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
t1.f2();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
t2.f1();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
t2.f2();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
三、除此之外还有一个很有意思的问题:
为什么在 static synchronized 修饰的方法中为什么不能调用notify()与notifyall()方法?
我想够了挺久的,最后发现
public final native void notify();
public final native void notifyAll();
这俩没有用static修饰。