在使用多线程程序时,会发现一个问题,就是共享资源的竞争。当一个共享资源被多个线程同时访问,这个共享资源就可能遭到破坏。而存在竞争状态多线程程序是不安全的。这时,我们需要一个创建临界区来防止多个线程同时进入程序的某一个特定部分。
synchronized关键字
锁是一种实现资源排他使用机制。一个同步方法在执行之前需要加锁。而synchronized是一个同步锁。它即可以修饰方法,也可以修饰类。
1)修饰一段代码块的时候,作用对象为该方法的当前对象。
2)修饰实例方法的时候,作用对象为该方法的当前对象。
3)修饰静态方法的时候,作用对象为这个类。
1)修饰一段代码块
synchronized修饰一段代码块,需要在代码块前加上synchronized,一般形式为:
synchronized(expr){
statements;
}
expr为一个对象的引用。
public class UseThread {
public static void main(String[] args) {
Thread thread = new Thread() {
//实现run()方法
@Override
public void run() {
synchronized (this) {
method.method("A");
}
}
};
//调用strat方法启动线程
thread.start();
method.method("B");
}
static class method {
public static void method(String str) {
for (int i = 0; i < 100; i++) {
System.out.println("method " + str + " " + i);
}
}
}
}
2)修饰一个实例方法
synchronized修饰一个方法,需要在方法前加上synchronized,例如public synchronized void method()。synchronized作用范围是整个方法。
public synchronized void run() {
for (int i = 0; i < 100; i++) {
System.out.println("Task " + i);
}
}
注意:synchronized是不被继承的。假如父类有一个方法为public synchronized void method(),而继承这个父类的子类中,会默认为public void method(),需要同步的话,要显式地加上synchronized,或者调用父类的method()。
3)修饰一个静态方法
synchronized修饰一个静态方法,也是在方法前加上synchronized,例如public static synchronized void method()。synchronized作用范围是所有属于该类的对象。
static class method {
public static synchronized void method() {
for (int i = 0; i < 100; i++) {
System.out.println("method " + i);
}
}
}
synchronized修饰一个实例方法和修饰一个静态方法的区别:
虽然两者的synchronized的使用方式差别不大,但是上面也提到synchronized在两者里面的作用范围不同。
当synchronized修饰一个实例方法,可以防止多个线程同时运行该对象的synchronized方法,同一个类中的不同对象的对应synchronized方法仍可以被访问。当synchronized修饰一个静态方法,相当于防止多个线程同时访问该类的所有对象的对应synchronized方法。