java笔记(九):synchronized

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 0
Thread-1 0
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-0 synchronized  1
Thread-0 synchronized  2
Thread-0 synchronized  3
Thread-1 synchronized  4
Thread-1 synchronized  5
Thread-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  1
Thread-0 synchronized0  2
Thread-0 synchronized0  3
Thread-1 synchronized1  4
Thread-1 synchronized1  5
Thread-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  2
Thread-0 synchronized0  2
Thread-1 synchronized1  3
Thread-0 synchronized0  4
Thread-1 synchronized1  5
Thread-0 synchronized0  6
* /

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值