Java的synchronized关键字,主要用来保证线程安全,即每次运行的结果与单个线程运行的结果一的致,避免执行结果出现二义性。当一个线程获得synchronized修饰代码时,其他线程对该代码访问将被阻塞,同一时间只允许一个线程访问该代码。
Java中synchronized关键字用法主要有两种:
- synchronized成员方法。
- synchronized修饰代码块。
使用synchronized关键字,最重要的是搞清楚,锁是加在哪个对象身上。
例子1:
package test;
public class SyncDemo1 extends Thread {
private int threadNo;
public SyncDemo1(int threadNo) {
this.threadNo = threadNo;
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new SyncDemo1(i).start();
Thread.sleep(1);
}
}
@Override
public synchronized void run() {
for (int i = 0; i < 100; i++) {
System.out.println("No." + (threadNo + 1) + ": " + (i + 1));
}
}
}
上面 代码原意是启动10个线程,每个线程打印当前线程号并输出1到100,并且保证 每个线程执行完了,才会去执行其他线程。然而程序执行结果并没有达到预期的效果。synchronized成员方法,控制类成员变量的访问。
上面例子中每个线程持有当前线程对象,显然起不到同步的作用。上面run方法等价于
@Override
public synchronized void run() {
synchronized (this) {
for (int i = 0; i < 100; i++) {
System.out.println("No." + (threadNo + 1) + ": " + (i + 1));
}
}
}
为了保证10个线程持有相同的锁对象,我们将代码修改如下:
package test;
public class SyncDemo2 extends Thread {
private int threadNo;
private static Object lock = new Object();
public SyncDemo2(int threadNo) {
this.threadNo = threadNo;
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new SyncDemo2(i).start();
Thread.sleep(1);
}
}
@Override
public void run() {
synchronized (lock) {
for (int i = 0; i < 100; i++) {
System.out.println("No." + (threadNo + 1) + ": " + (i + 1));
}
}
}
}
这样所有的线程持有同一对象lock的锁,达到每个线程内按顺序执行的结果。
我们也可以使用静态的synchronized方法,将锁加在Class上:
package test;
public class SyncDemo3 extends Thread {
private int threadNo;
public SyncDemo3(int threadNo) {
this.threadNo = threadNo;
}
public static void main(String[] args) throws Exception {
for (int i = 1; i < 10; i++) {
new SyncDemo3(i).start();
Thread.sleep(1);
}
}
public static synchronized void fun(int threadNo) {
for (int i = 0; i < 100; i++) {
System.out.println("No." + (threadNo + 1) + ":" + (i + 1));
}
}
@Override
public void run() {
fun(threadNo);
}
}
等价于:
@Override
public void run() {
synchronized (LockDemo1.class) {
for (int i = 0; i < 100; i++) {
System.out.println("No." + (threadNo + 1) + ": " + (i + 1));
}
}
}