Java多线程编程核心技术(第3版)
上QQ阅读APP看书,第一时间看更新

2.2.14 静态同步:synchronized方法与synchronized(class)代码块

synchronized关键字还可以应用在静态方法上,如果这样写,那是对当前的*.java文件对应的Class类的对象进行持锁,Class类的对象是单例的,更具体地说,在静态方法上使用synchronized关键字声明同步方法时,是使用当前静态方法所在类对应Class类的单例对象作为锁的。

测试项目在synStaticMethod中,类文件Service.java代码如下:


package service;

public class Service {

synchronized public static void printA() {
    try {
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + "在" + System.currentTimeMillis() + "进入printA");
        Thread.sleep(3000);
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + "在" + System.currentTimeMillis() + "离开printA");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    synchronized public static void printB() {
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                + "在" + System.currentTimeMillis() + "进入printB");
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                + "在" + System.currentTimeMillis() + "离开printB");
}

}

自定义线程类ThreadA.java代码如下:


package extthread;

import service.Service;

public class ThreadA extends Thread {
@Override
public void run() {
    Service.printA();
}

}

自定义线程类ThreadB.java代码如下:


package extthread;

import service.Service;

public class ThreadB extends Thread {
@Override
public void run() {
    Service.printB();
}
}

运行类Run.java代码如下:


package test;

import service.Service;
import extthread.ThreadA;
import extthread.ThreadB;

public class Run {

public static void main(String[] args) {

    ThreadA a = new ThreadA();
    a.setName("A");
    a.start();

    ThreadB b = new ThreadB();
    b.setName("B");
    b.start();

}

}

程序运行结果如图2-43所示。

图2-43 运行结果是同步效果

虽然运行结果与将synchronized关键字加到非static静态方法上的使用效果一样,都是同步的效果,但还是有本质上的不同。synchronized关键字加到static静态方法上是将Class类的对象作为锁,而synchronized关键字加到非static静态方法上是将方法所在类的对象作为锁。

为了验证不是同一个锁,创建新的项目synTwoLock,文件Service.java代码如下:


package service;

public class Service {

synchronized public static void printA() {
    try {
        System.out.println("线程名称为:" + Thread.currentThread().getName()
            + "在" + System.currentTimeMillis() + "进入printA");
        Thread.sleep(3000);
        System.out.println("线程名称为:" + Thread.currentThread().getName()
            + "在" + System.currentTimeMillis() + "离开printA");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

synchronized public static void printB() {
    System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
        + System.currentTimeMillis() + "进入printB");
    System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
        + System.currentTimeMillis() + "离开printB");
}

synchronized public void printC() {
    System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
        + System.currentTimeMillis() + "进入printC");
    System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
        + System.currentTimeMillis() + "离开printC");
}

}

自定义线程类ThreadA.java代码如下:


package extthread;

import service.Service;

public class ThreadA extends Thread {
private Service service;

public ThreadA(Service service) {
    super();
    this.service = service;
}

@Override
public void run() {
    service.printA();
}

}

自定义线程类ThreadB.java代码如下:


package extthread;

import service.Service;

public class ThreadB extends Thread {
private Service service;

public ThreadB(Service service) {
    super();
    this.service = service;
}

@Override
public void run() {
    service.printB();
}
}

自定义线程类ThreadC.java代码如下:


package extthread;

import service.Service;

public class ThreadC extends Thread {

private Service service;

public ThreadC(Service service) {
    super();
    this.service = service;
}

@Override
public void run() {
    service.printC();
}
}

运行类Run.java代码如下:


package test;

import service.Service;
import extthread.ThreadA;
import extthread.ThreadB;
import extthread.ThreadC;

public class Run {

public static void main(String[] args) {

    Service service = new Service();

    ThreadA a = new ThreadA(service);
    a.setName("A");
    a.start();

    ThreadB b = new ThreadB(service);
    b.setName("B");
    b.start();

    ThreadC c = new ThreadC(service);
    c.setName("C");
    c.start();

}

}

程序运行结果如图2-44所示。

图2-44 printC()方法为异步运行

异步的原因是持有不同的锁,一个是将Service类的对象作为锁,另一个是将Service类对应Class类的对象作为锁,线程AB和C是异步的关系,而线程A和B是同步的关系。