java synchronized使用

Posted FEI_>.<_JI

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java synchronized使用相关的知识,希望对你有一定的参考价值。

java synchronized

  基本上,所有并发的模式在解决线程冲突问题的时候,都是采用序列化共享资源的方案。这意味着在给定时刻只允许一个任务访问该资源。这个一般通过在代码上加一条锁语句实现,因为锁语句产生一种互斥排斥的效果,这种机制常常被称为互斥机制

线程是簇拥在共享资源门前,并不是排队进入,可以通过yield()setPriority()来给线程调度提供建议,但这些建议未必会有多大的效果。这取决与你的具体平台和vm的实现:)--//from 《think in java》

  java中提供关键字synchronized,为防止资源冲突提供内置支持。当他用来修饰一个方法或者代码块的时候,能够保证在同一时间最多只有一个线程访问执行该方法或者代码块;关于synchronized用于方法,用于代码块,用于静态方法可以参考博客Java中Synchronized的用法

 


 

sychronized(this)的理解

  this它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。=.= 那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱  :)  使用三个实例加强理解:

 

示例一


public
class Thread1 implements Runnable { public void run() { synchronized(this) { //枷锁 for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
            try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } } } }
public static void main(String[] args) { Thread1 t1 = new Thread1(); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t1, "B"); //A线程先执行完毕,再执行B线程 ta.start(); tb.start(); } }

结果: 
     A synchronized loop 0 
     A synchronized loop 1 
     A synchronized loop 2 
     A synchronized loop 3 
     A synchronized loop 4 
     B synchronized loop 0 
     B synchronized loop 1 
     B synchronized loop 2 
     B synchronized loop 3 
     B synchronized loop 4

 

 

示例二:

 

public class Thread2 {
    public void m4t1() {
        synchronized (this) {//枷锁1
            int i = 5;
            while (i-- > 0) {
                System.out
                        .println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                }
            }
        }
    }

    public void m4t2() {
        synchronized (this) {//枷锁2
            int i = 5;
            while (i-- > 0) {
                System.out
                        .println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(300);//休眠短一些
                } catch (InterruptedException ie) {
                }
            }
        }
    }

    public static void main(String[] args) {
        final Thread2 myt2 = new Thread2();
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                myt2.m4t1();//A线程只调用了枷锁的m4t1(),B线程调用枷锁的m4t2(),仍然需要等待A执行完毕
            }
        }, "A");
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                myt2.m4t2();
            }
        }, "B");
        t1.start();
        t2.start();
    }
}

结果

A : 4
A : 3
A : 2
A : 1
A : 0
B : 4
B : 3
B : 2
B : 1
B : 0
也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

 

 

示例三

public class Thread3 {
    public void m4t1() {
        synchronized (this) {//枷锁
            int i = 5;
            while (i-- > 0) {
                System.out
                        .println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                }
            }
        }
    }

    public void m4t2() {int i = 5;//不枷锁
            while (i-- > 0) {
                System.out
                        .println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(300);
                } catch (InterruptedException ie) {
                }
            }
    }

    public static void main(String[] args) {
        final Thread3 myt3 = new Thread3();
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                myt3.m4t1(); //
            }
        }, "A");
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                myt3.m4t2();
            }
        }, "B");
        t1.start();
        t2.start();
    }
}

结果:   (具有不确定性)

A : 4
B : 4
B : 3
A : 3
B : 2
B : 1
A : 2
B : 0
A : 1
A : 0
当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

 

总结:所有的对象都有单一的锁(也成为监视器)。当在对象上调用任意的synchronized方法的时候,此对象都被加锁,这时调用该对象上其他的synchronized方法只有等待前一个方法调用完毕并释放所之后才能调用。

   注意:在使用并发的时候,将域设置为private时非常重要的。否则,synchronized关键字就不能防止其他任务直接访问域,这样就会产生冲突。

 

one more thing:

  一个任务可以多次获得对象的锁,如果一个方法在同一对象上调用了第二个方法,后者又调用了同一对象上的另一个方法,就会发生这样的情况。JVM负责跟踪对象被加锁的次数。如果一个对象被完全解锁,其计数变为0.每当任务离开一个synchronized方法,计数递减,当计数为0,锁被完全释放,此时别的任务就可以使用此资源:)

  针对每一个类,也有一个锁(作为类的class对象的一部分),所以synchronized static方法可以在类的范围类防止对static数据的并发访问。

 

以上是关于java synchronized使用的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程实战—–synchronized

多线程 Thread 线程同步 synchronized

Java初识方法

Java多线程与并发库高级应用-工具类介绍

Java多线程与并发库高级应用-工具类介绍

java并发线程锁技术的使用