synchronized关键字

参考自《实战Java高并发程序设计》

synchronized的三种用法:

  • 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁
  • 直接作用于实例方法:相当于给当前实例加锁
  • 直接作用于静态方法:相当于给当前类加锁

给对象加锁

下面这段代码会执行i++操作10000000次,由于创建了两个线程,我们期望打印的结果是20000000

public class AccountingSync implements Runnable{
    static AccountingSync instance=new AccountingSync();
    static int i=0;

    @Override
    public void run() {
        for(int j=0;j<10000000;j++){
            //给instance对象加锁
            synchronized (instance){
                i++;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(instance);
        Thread t2=new Thread(instance);
        t1.start();
        t2.start();
        t1.join();//join:等待当前执行的线程结束,结束后马上执行该线程
        t2.join();
        System.out.println(i);
    }
}

每当线程进入被synchronized关键字修饰的代码段,都会请求instance实例的锁。如果当前有其它线程正持有这把锁,那么新来的线程就必须等待。这样就保证了每次只有一个线程执行i++操作

给实例方法加锁

上述代码也可以这样写:

    public synchronized void increase(){
        i++;
    }

    @Override
    public void run() {
        for(int j=0;j<10000000;j++){
//            synchronized (instance){
//                i++;
//            }
            increase();
        }
    }

最终运行结果是和第一个例子一样的,这就是直接给实例方法加锁

给类加锁

如果上述代码的main方法中这样写:

Thread t1=new Thread(new AccountingSync);
Thread t2=new Thread(new AccountingSync);

这种同步方式是错误的!

前文的代码加的是对象锁,两个线程指向的两个对象,换言之,这两个线程使用的两把不同的锁

但只要把对象锁改成类的锁就行了

public static synchronized void increase(){
    i++;
}

这样就可以正确同步了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。