11.6Java多线程之线程同步

Java中线程同步是利用了加锁解锁方式实现的。加锁解锁之间的代码块为临界区,任何时候临界区只能有一个线程执行。
Java中使用了一个关键字对一个对象加锁:synchronized
以下例子证明了锁的应用:

package MyThread;

public class MyLock {
	    public static void main(String[] args) throws Exception {
	        Thread add = new AddThread();
	        Thread dec = new DecThread();
	        add.start();
	        dec.start();
	        add.join();
	        dec.join();
	        System.out.println(Counter.count);
	    }
}
class Counter {
    public static final Object lock = new Object();
    public static int count = 0;
}
class AddThread extends Thread {
    public void run() {
        for (int i=0; i<100; i++) {
            synchronized(Counter.lock) {
                Counter.count += 1;
                System.out.println(Counter.count);
            }
        }
    }
}
class DecThread extends Thread {
    public void run() {
        for (int i=0; i<100; i++) {
            synchronized(Counter.lock) {
                Counter.count -= 1;
                System.out.println(Counter.count);
            }
        }
    }
}

最终的结果为0。

synchronized(Counter.lock) { // 获取锁
    ...
} // 释放锁

该代码块结束后自动施法锁。
加锁解锁操作虽然解决了同步问题,但是并不能并发执行,因此效率下降。
注意:在操作同意对象时,加的锁必须是同一对象:

synchronized(Counter.lock1) {
                Counter.count += 1;
                System.out.println(Counter.count);
            }
synchronized(Counter.lock2) {
                Counter.count -= 1;
                System.out.println(Counter.count);
            }

上述例中描述错误,两者操作同一变量时加入的锁不一致,导致锁机制完全没有发挥效果,结果与不加锁一致。
但如果操作不同变量但加上同一把锁,会造成大大降低了执行效率。例如:

class AddStudentThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            synchronized(Counter.lock) {
                Counter.studentCount += 1;
            }
        }
    }
}

class DecStudentThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            synchronized(Counter.lock) {
                Counter.studentCount -= 1;
            }
        }
    }
}

class AddTeacherThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            synchronized(Counter.lock) {
                Counter.teacherCount += 1;
            }
        }
    }
}

class DecTeacherThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            synchronized(Counter.lock) {
                Counter.teacherCount -= 1;
            }
        }
    }
}

上述四个类中操作的是同一锁,但操作的变量不统一,于是造成效率降低。
因此对锁的使用需要:同一把锁操作同一变量。不同的锁操作不同的变量。

假如锁住的只是一条赋值语句,则需要进行锁操作吗?
答案是不需要,因为只需要赋值一次,没有存在同步问题。

public void set(int m) {
    synchronized(lock) {
        this.value = m;
    }
}

就可修改为

public void set(int m) {
        this.value = m;
}

synchronized关键字还可以修饰方法,当它修饰方法时,表示整个方法内部是线程同步块,而加锁对象是this,即该对象的实例。另外当修饰静态方法时,被锁住的是该类的Class。

public synchronized void add(int n) { // 锁住this
    count += n;
} // 解锁

等同于:

public void add(int n) {
    synchronized(this) { // 锁住this
        count += n;
    } // 解锁
}

而:

public synchronized static void test(int n) {
    ...
}

等同于:

public class Counter {
    public static void test(int n) {
        synchronized(Counter.class) {
            ...
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值