java笔记(九):synchronized

来源:互联网 发布:移动硬盘与mac连接 编辑:程序博客网 时间:2024/05/16 12:05

synchronized常用来保证线程安全,作为java中比较复杂的一个关键字,有必要专门进行一次总结。
大体上来说,用该关键字修饰方法或代码块时,能保证同一时刻,只能有一个线程访问该属性或代码块。

关于synchronized(this)同步代码块,有如下两点需要注意:

  • 对于同一个对象的所有synchronized(this)同步代码块,只能有某一个该代码块被某一个线程执行
  • 某个线程访问synchronized(this)代码块时,其他线程仍可访问非synchronized(this)代码块

另外需要强调的是,以上规则只对同一个对象实例化的多个线程有效,即多线程需要由同一个对象实例化。

public class Test{    public static void main(String[] arcgs) throws Exception {        //用来实例化的对象        ThreadTest threadTest = new ThreadTest();        Thread thread1 = new Thread(threadTest);        Thread thread2 = new Thread(threadTest);        thread1.start();        thread2.start();    }}class ThreadTest implements Runnable{    private int count = 0;    public void run(){        synchronized(this){            for(int i = 0;i<4;i++){                count++;                System.out.println(Thread.currentThread().getName()+" "+count);            }        }    }}/*** Thread-0 1* Thread-0 2* Thread-0 3* Thread-0 4* Thread-1 5* Thread-1 6* Thread-1 7* Thread-1 8* /

当然对于非synchronized(this)代码块,其他线程仍可以执行。

public class Test{    public static void main(String[] arcgs) throws Exception {        //用来实例化的对象        ThreadTest threadTest = new ThreadTest();        Thread thread1 = new Thread(threadTest);        Thread thread2 = new Thread(threadTest);        thread1.start();        thread2.start();    }}class ThreadTest implements Runnable{    private int count = 0;    public void run(){        for(int i = 0;i<3;i++){            System.out.println(Thread.currentThread().getName()+" "+i);        }        synchronized(this){            for(int i = 0;i<3;i++){                count++;                System.out.println(Thread.currentThread().getName()+" synchronized "+" "+count);            }        }    }}/**Thread-0 0Thread-1 0Thread-0 1Thread-1 1Thread-0 2Thread-1 2Thread-0 synchronized  1Thread-0 synchronized  2Thread-0 synchronized  3Thread-1 synchronized  4Thread-1 synchronized  5Thread-1 synchronized  6* /

为了更好地理解synchronized关键字修饰方法的意义,看下面的例子:

ThreadTest threadTest = new ThreadTest();Thread thread1 = new Thread(new Runnable(){    public void run(){        threadTest.test0();    }});Thread thread2 = new Thread(new Runnable(){    public void run(){        threadTest.test1();    }});thread1.start();thread2.start();class ThreadTest {    private int count = 0;    public synchronized void test0(){        for(int i = 0;i<3;i++){            count++;            System.out.println(Thread.currentThread().getName()+" synchronized0 "+" "+count);        }    }    public synchronized void test1(){        for(int i = 0;i<3;i++){            count++;            System.out.println(Thread.currentThread().getName()+" synchronized1 "+" "+count);        }    }}/**Thread-0 synchronized0  1Thread-0 synchronized0  2Thread-0 synchronized0  3Thread-1 synchronized1  4Thread-1 synchronized1  5Thread-1 synchronized1  6* /

虽然没有实现Runnable接口,但由于是在建立的内部类中运行,因此仍然实现了单线程的访问。

注意理解synchronized(this)的意思。
下面的代码等做到单线程执行吗?

ThreadTest threadTest = new ThreadTest();Thread thread1 = new Thread(new Runnable(){    public void run(){        synchronized(this){            threadTest.test0();        }    }});Thread thread2 = new Thread(new Runnable(){    public void run(){        synchronized(this){            threadTest.test1();        }    }});thread1.start();thread2.start();class ThreadTest {    private int count = 0;    public void test0(){        for(int i = 0;i<3;i++){            count++;            System.out.println(Thread.currentThread().getName()+" synchronized0 "+" "+count);        }    }    public void test1(){        for(int i = 0;i<3;i++){            count++;            System.out.println(Thread.currentThread().getName()+" synchronized1 "+" "+count);        }    }}/** 一种可能的输出结果Thread-1 synchronized1  2Thread-0 synchronized0  2Thread-1 synchronized1  3Thread-0 synchronized0  4Thread-1 synchronized1  5Thread-0 synchronized0  6* /

原因在于,synchronized(this)的目的是获取当前对象的锁,但代码中两次new Thread()中的参数是新建的两个内部类,无法起到互斥的作用。只需要将synchronized(this)改为synchronized(threadTest),就可以得到单线程运行的结果,如下:

/** 一种可能的输出结果Thread-0 synchronized0  1Thread-0 synchronized0  2Thread-0 synchronized0  3Thread-1 synchronized1  4Thread-1 synchronized1  5Thread-1 synchronized1  6* /

在 Java 中,不光是类对象,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。