大家都 知道一个运行着的程序就是一个进程,而进程之间的内存空间是相互独立的,所以两个进程只要不存在操作同一公共资源(如同时操作同一个文件)的情况,也就不 会存在进程安全的问题。但线程就不一样了,在同一个进程中的不同线程是完全共享资料的,他们可以访问同一个内存区域,所以也就有一个多个线程同时读写一个 内在地址(或关联数据)时产生的不可预期的问题了,这就是所谓的线程不安全。如果有下面的程序:
public class GetID {
private static int id = 0;
public static int getId() {
id = id + 1;
return id;
}
}
从程序我们可以知道,类GetID的功能主要是分配一个唯一的ID号,但代码id = id + 1在多线程运行时可能会有冲突的情况,可能两个线程同时取得到了id然后再加一,即可能同时取得到相同的id值,虽然这种问题发生的可能性极低,但一但发生可能会产生非常严重的问题。
现在的程序都应该是多线程的,特别是CPU已经多核化了,所以在进行编程时需要特别的注意线程安全性。如果你学习过操作系统的知道就会知道p操作和v操作了,p操作是进入线程同步(就是对同一段程序不能有两个线程进入),而v操作是退出线程同步。但使用p操作和v操作需要注意在异常时仍然需要进行v操作,比如下面的代码:
p(); // 开始线程同步
try {
// TODO ... do something ...
} finally {
v(); // 退出线程同步
}
当然在Java中就不需要如此麻烦了,因为并不是每一个程序员都会十分注意地会将v操作放到finally段中,所以Java当中提供了一种更好的同步方法:
public static class SyncClass {
private static int uid = 0;
private static Object syncObject = new Object();
public static int getUid() {
synchronized (syncObject) {
return uid++;
}
}
}
类似于上面的代码,在Java中使用关键字synchronized来进行同步,这种方法非常直观而且很安全,即使程序员没异常处理的意识也不会引起问题。在上面的代码中,程序通过对对象syncObject来进行同步操作,也就是说只要是使用syncObject对象的同步代码即使在多个线程中也只会一个线程能够进行操作。
下面的用法也可以进行线程同步:
public static class SyncClass2 {
private static int uid = 0;
public static synchronized int getUid() {
return uid++;
}
public static int getUid2() {
synchronized (SyncClass2.class) {
return uid++;
}
}
}
或是使用下面的方法进行同步:
public static class SyncClass3 {
public synchronized int getIntItem() {
return 0;
}
public int getIntItem2() {
synchronized (this) {
return 0;
}
}
}
但需要注意的是上面的两个同步方法是不一致的,一个是对类本身进行同步,另一个是对this对象进行同步,所以这两个方法请不要同时使用,因为这两个方法同时使用会非常容易引起误会(让人误解为一个static函数的同步方法会和一个普通的同步方法进行真正的同步),就如下面的程序:
public static class SyncClass4 {
public static synchronized int getIntItem() {
return 0;
}
public synchronized int getIntItem2() {
return 0;
}
}
在上面的程序中,方法getIntItem和方法getIntItem2并不会进行同步,因为一个是static方法,而另一个不是。
更多的选择进行线程同步:Lock,Lock是一个非常有用的Java接口,类似于p、v操作来进行线程同步,下面是一种Lock的使用方法:
public static class SyncClass5 {
private static int uid = 0;
private static Lock lock = new ReentrantLock();
public static int getUid() {
lock.lock();
try {
return uid++;
} finally {
lock.unlock();
}
}
}
这里的lock及unlock方法都类似于p操作及v操作,所以也需要注意将unlock方法放到finally段中去。这种同步的方法很好但有些场合下就不是很合适了,比如:
public static class SyncClass6 {
private static Lock lock = new ReentrantLock();
public static int readInt() {
lock.lock();
try {
return 0;
} finally {
lock.unlock();
}
}
public static void writeInt(int value) {
lock.lock();
try {
// write value
} finally {
lock.unlock();
}
}
}
因为在多个线程读的时候也只有一个线程能进入读的区域,这样影响了读的性能,会使程序变慢。下面是另一个更好些的写法:
public static class SyncClass7 {
private static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public static int readInt() {
readWriteLock.readLock().lock();
try {
return 0;
} finally {
readWriteLock.readLock().unlock();
}
}
public static void writeInt(int value) {
readWriteLock.writeLock().lock();
try {
// write value
} finally {
readWriteLock.writeLock().unlock();
}
}
}
因为多个readInt方法可以由多个线程同时进入,这样可以让程序跑地更快。
关于多线程的知识还有很多很多,大家可以参看这方面的书籍或资料,去看看Java的相关的源代码也非常有益,应该能学到很多很多东西。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jht5945/archive/2008/04/08/2260198.aspx
分享到:
相关推荐
java线程同步java线程同步java线程同步
java多线程同步互斥访问实例,对于初学者或是温故而知新的同道中人都是一个很好的学习资料
Java多线程同步论文.doc
Java线程(二):线程同步synchronized和volatile 详细讲解Java 同步的原理技术资料
JAVA代码采用线程来实现数据库的主从同步更新
Java线程:线程的同步-同步方法 Java线程:线程的同步-同步块 Java线程:并发协作-生产者消费者模型 Java线程:并发协作-死锁 Java线程:volatile关键字 Java线程:新特征-线程池 Java线程:新特征-有返回值的线程 ...
文件简述了java中线程同步的具体用法,希望能对您有点小用,不足之处,请您喷。
java线程同步实例,哲学家思考的代码实现,应该是一个比较好的例子
java 多线程同步方法的实例 java 多线程同步方法的实例 java 多线程同步方法的实例
Java线程:线程的同步-同步方法 Java线程:线程的同步-同步块 Java线程:并发协作-生产者消费者模型 Java线程:并发协作-死锁 Java线程:volatile关键字 Java线程:新特征-线程池 Java线程:新特征-有返回值的...
多线程注意:wait()方法的调用要有判定条件常用 while () obj.wait(timeout, nanos); ... // Perform action appropriate to condition } synchronized会影响共享数据,但对其他语句的执行不会有规律了!
Java多线程同步.pdf
Java线程:线程的同步 33 一、 同步方法 35 二、 同步块 36 三、 volatile关键字 38 四、 使用synchronized关键字要注意以下四点 39 五、 关于同步和锁定的一些问题 41 Java线程:并发协作-线程的交互 47 Java线程:...
java多线程同步分析java多线程同步分java多线程同步分析析java多线程同步分析java多线程同步分析
java线程同步
Java多线程同步具体实例讲解 .doc
Java多线程机制 9.1 Java中的线程 9.2 Thread的子类创建线程 ...9.6 线程同步 9.7 在同步方法中使用wait()、notify 和notifyAll()方法 9.8 挂起、恢复和终止线程 9.9 计时器线程Timer 9.10 线程联合 9.11 守护线程
Java多线程同步具体实例.doc
java线程第二版中英文 java线程第二版中英文 线程并不是新的概念:许多操作系统和语言都支持它们。在Java出现以前,似乎人人都在谈论线程,却很少有人使用它。用线程编程是技巧性很强的且不可移植。 而在Java中却...
java中线程同步方法的总结,描述的很详细。