第二章-对象及变量的并发访问-第二篇

本文深入探讨了Java中synchronized关键字的使用方式及其对同步方法和代码块的影响。通过实例对比了静态方法锁与非静态方法锁的区别,并分析了String常量池特性对同步操作的影响。

静态同步方法synchronized方法和synchronized(class)代码块

synchronized关键字嫁到static方法上的是给class类上锁,而synchronized加到非静态方法上是给对象上锁。

public class MainClass {
    synchronized public void printStringA()  {
        String a = Thread.currentThread().getName();
        String b = Thread.currentThread().getName() + "a";
        System.out.println(a);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(b);
    }

    synchronized  public static void printStringB() {
        String a = Thread.currentThread().getName();
        String b = Thread.currentThread().getName() + "b";
        System.out.println(a);
        System.out.println(b);
    }
}

public class ThreadA extends Thread {
    private MainClass mainClass;

    public ThreadA(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
            mainClass.printStringA();
    }
}

public class ThreadB extends Thread {
    private MainClass mainClass;

    public ThreadB(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
            mainClass.printStringB();
    }
}

public class RunClass {
    public static void main(String[] args) throws InterruptedException {
        MainClass mainClass = new MainClass();
        ThreadA threadA = new ThreadA(mainClass);
        threadA.start();
        ThreadB threadB =new ThreadB(mainClass);
        threadB.start();
    }
}   

输出结果

Thread-0
Thread-1
Thread-1b
Thread-0a

从输出结果可以看出两个方法的执行是异步执行的,异步执行的原因是一个是对象锁,一个是class类锁。 如果还是不理解,请看下面的方法。

public class MainClass {
    synchronized public static void printStringA()  {
        String a = Thread.currentThread().getName();
        String b = Thread.currentThread().getName() + "a";
        System.out.println(a);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(b);
    }

   synchronized public static void printStringB() {
        String a = Thread.currentThread().getName();
        String b = Thread.currentThread().getName() + "b";
        System.out.println(a);
        System.out.println(b);
    }
}

public class RunClass {
    public static void main(String[] args) throws InterruptedException {
        MainClass mainClass = new MainClass();
        MainClass mainClass2 = new MainClass();
        ThreadA threadA = new ThreadA(mainClass);
        threadA.start();
        Thread.sleep(100);
        ThreadB threadB =new ThreadB(mainClass2);
        threadB.start();
    }
}   

输出结果

Thread-0
Thread-0a
Thread-1
Thread-1b

一样是同步的,这就是类锁和对象锁的区别。

数据类型String的常量池特性

先看程序

public class MainClass {
    public void printStringB(String stringParam) {
        try {
            synchronized (stringParam) {
                while (true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }
        } catch ( InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

public class ThreadA extends Thread {
    private MainClass mainClass;

    public ThreadA(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
            mainClass.printStringB("AA");
    }
}

public class ThreadB extends Thread {
    private MainClass mainClass;

    public ThreadB(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
        mainClass.printStringB("AA");
    }
}

public class RunClass {
    public static void main(String[] args) throws InterruptedException {
        MainClass mainClass = new MainClass();
        MainClass mainClass2 = new MainClass();
        ThreadA threadA = new ThreadA(mainClass);
        threadA.setName("a");
        threadA.start();
        ThreadB threadB =new ThreadB(mainClass2);
        threadB.setName("b");
        threadB.start();

    }
}    

输出结果

a
a
a
a
a
a
...

不断的输出a,线程b根本没得到执行,这是为什么呢? 因为string的两个值都是AA,这就是因为string常量池带来的影响,AA在string常量池的缓存范围内,所以同步方法持有的是同一个对象,因此线程b得不到执行。

大多数情况下不能使用string对象作为锁对象,改用其他的,比如object对象。

其他常量池的情况也得小心,比如整形。

public class MainClass {
    public void printStringB(Object object) {
        try {
            synchronized (object) {
                while (true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }
        } catch ( InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

public class ThreadA extends Thread {
    private MainClass mainClass;

    public ThreadA(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
            mainClass.printStringB(new Object());
    }
}

public class ThreadB extends Thread {
    private MainClass mainClass;

    public ThreadB(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
        mainClass.printStringB(new Object());
    }
}

输出结果

b
a
b
a
b
a
b
a
...

转载于:https://my.oschina.net/jiansin/blog/1931042

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值