您的位置:首页 > 编程语言 > Java开发

Java中的多线程(二)之多线程同步

2014-03-16 09:36 369 查看
多线程同步synchronized

synchronized是Java多线程中比较重要的关键字之一,它可以修饰一个方法或者一段代码块,用以保证每一次最多只有一个线程去访问,是Java实现多线程同步最基本的方式之一

eg:

public class TestThread {
private int value;
public static void main(String[] args) {
final TestThread tt = new TestThread();
Thread t1 = new Thread(){
@Override
public void run() {
for(int i=0;i<10;i++){
tt.inc(this.getName());
}
}
};
t1.start();

Thread t2 = new Thread(){
@Override
public void run() {
for(int i=0;i<10;i++){
tt.inc(this.getName());
}
}
};
t2.start();
}
public void inc(String threadName) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
System.out.println(threadName + "-->" + value++);
}
}
上述例子开辟了两个线程去访问同一个对象的inc方法,由于没有使用synchronized来进行同步,看一下输出结果是什么

Thread-0-->0

Thread-1-->1

Thread-1-->2

Thread-0-->3

Thread-1-->4

Thread-0-->5

Thread-0-->6

Thread-1-->6

Thread-1-->8

Thread-0-->7

Thread-0-->9

Thread-1-->10

Thread-1-->11

Thread-0-->12

Thread-1-->13

Thread-0-->13

Thread-1-->15

Thread-0-->14

Thread-1-->16

Thread-0-->16

我们发现,有些数字会出现重复,这个与我们预期的结果出现了偏差,那么把synchronized加上以后会怎么样呢?

public synchronized void inc(String threadName) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
System.out.println(threadName + "-->" + value++);
}
结果如下:

Thread-0-->0

Thread-1-->1

Thread-0-->2

Thread-1-->3

Thread-0-->4

Thread-1-->5

Thread-0-->6

Thread-1-->7

Thread-0-->8

Thread-1-->9

Thread-0-->10

Thread-1-->11

Thread-1-->12

Thread-0-->13

Thread-1-->14

Thread-0-->15

Thread-1-->16

Thread-0-->17

Thread-1-->18

Thread-0-->19

这个结果应该是比较满意的,那么synchronized到底做了啥呢?其实,在Java中每一个对象都有一个与之关联的监视器对象,它允许线程对监视器进行加锁和解锁,所以synchronized方法就是对某一个对象进行了加锁,这个对象就是该类的Class对象。

而synchronized如果只是修饰了一小段代码块,那么它加锁的对象需要手动的添加。

eg:

Object o = new Object();
synchronized (o) {
//doSomething
}
这个其实就是锁住了对象o,它能保证的就是任何其它没有拿到监视器对象上的锁的线程都无法访问此段代码。需要注意的是,这种使用方式经常会出现问题,原因在于一个类的Class对象只有一份,所以它的锁也是唯一的,但是手动关联加锁对象经常会出现这个锁不是唯一的情况,比如Object  o是在一个方法中定义的,那么任何线程访问这个方法时都会创建一份新的Object,这个时候每个线程需要的锁都是独立的,加锁也就失去了意义。

eg:

public void inc(String threadName) {
Object o = new Object();
synchronized (o) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
System.out.println(threadName + "-->" + value++);
}
}
这段代码演示了synchronized失效的一种情景,每次访问都会产生一个新的o对象,synchronized(o)加锁失去了意义。同理,下段代码与synchronized方法效果相同:

public void inc(String threadName) {
synchronized (TestThread.class) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
System.out.println(threadName + "-->" + value++);
}
}
OK,我们知道在计算机中通常不只有主存,可能还会有缓存、寄存器等其它存储结构。第一节刚开始的时候就说了Java的多线程并发是通过共享内存实现的,而实际情况可能是,线程1要获取一个变量i的值,它会先去缓存中读取,如果缓存中存在,就不会再去主存中读取了,而每个线程都有一份缓存,所以如果缓存更新不及时的话,就会造成多个线程获取的值存在偏差的情况,因此线程获得锁时实际上是将缓存中的内容设置成了无效状态,直接从主存中读取,同样的,当失去锁时,它会将缓存直接写到主存中,从而实现”同步“。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐