关于Java同步机制中synchronized同步方法

Java的同步机制中被synchronized关键字修饰的有两种,一种是同步块,另一种是同步方法。现在直说同步方法
 
在同步方法中,被synchronized关键字修饰的方法的作用域有两种:
        a.    作用域是某个实例内,synchronized Method(){ }可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象中有多个synchronized方法,只要一个线程访问了其中一个synchronized方法,其他线程不能同时访问这个对象中任何一个synchronized方法)。这时不同的对象实例中的synchronized方法是互不干扰的,也就是说,其他线程照样可以访问相同类的另一个对象实例中的synchronized方法。
                也就是说,只被synchronized修饰的方法,作用域只在单个对象中,进程的同步机制只在单个对象中,不同对象中的synchronized方法是不相互干扰的
       Eg:
 public class ThreadSafeTest extends Thread implements Runnable {
    private static int num = 1;

    public ThreadSafeTest(String name) {
        setName(name);
    }

    public void run() {
        sell(getName());
        
    }
    
    private synchronized void sell(String name){
        if (num > 0) {
            System.out.println(name + ": 检测票数大于0");
            System.out.println(name + ": \t正在收款(大约5秒完成)。。。");
            try {
                Thread.sleep(5000);
                System.out.println(name + ": \t打印票据,售票完成");
                num--;
                printNumInfo();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(name+": 没有票了,停止售票");
        }
    }

    private void printNumInfo() {
        System.out.println("系统:当前票数:" + num);
        if (num < 0) {
            System.out.println("警告:票数低于0,出现负数");
        }
    }

    public static void main(String args[]) {
        try {
            new ThreadSafeTest("售票员李XX").start();
            Thread.sleep(2000);
            new ThreadSafeTest("售票员王X").start();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
上述代码中同步方法只被synchronized修饰,所以这个同步方法只能用于单个对象中。
 
        运行的结果是:并没有达到线程间同步的目的
  
b.    作用域是某个类的范围,这个时候方法就需要synchronized static来修饰了。synchronized static Method(){ }用于防止多个线程同时访问这个类中的synchronized static方法,它是对类的所有对象实例起作用
            也就是说,某个方法被synchronized static修饰后,这个方法就对所有的对象实例起作用了,只要有一个对象实例调用了该方法,其他的对象实例只能等该方法解锁后才能调用该方法,从而起到线程之间的同步问题。
Eg:
 把上述代码的sell()方法改为synchronized static,printNumInfo()改为static后就可以实现线程同步问题了
 public class ThreadSafeTest extends Thread implements Runnable {
    private static int num = 1;

    public ThreadSafeTest(String name) {
        setName(name);
    }

    public void run() {
        sell(getName());
        
    }
    
    private synchronized static void sell(String name){
        if (num > 0) {
            System.out.println(name + ": 检测票数大于0");
            System.out.println(name + ": \t正在收款(大约5秒完成)。。。");
            try {
                Thread.sleep(5000);
                System.out.println(name + ": \t打印票据,售票完成");
                num--;
                printNumInfo();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(name+": 没有票了,停止售票");
        }
    }

    private static void printNumInfo() {
        System.out.println("系统:当前票数:" + num);
        if (num < 0) {
            System.out.println("警告:票数低于0,出现负数");
        }
    }

    public static void main(String args[]) {
        try {
            new ThreadSafeTest("售票员李XX").start();
            Thread.sleep(2000);
            new ThreadSafeTest("售票员王X").start();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 运行的结果达到了线程间的同步

注意:synchronized关键字不能继承,也就是说,基类的方法synchronized f(){ }在继承类中不自动生成synchronized f() { },而变成了f() { }。继承类需要你显示的制定他的某个方法是synchronized方法。

原文地址:https://www.cnblogs.com/Skyar/p/3079418.html