值得注意的一点是,QObject
及其所有子类都不是线程安全的(但都是可重入的)。因此,你不能有两个线程同时访问一个QObject
对象,除非这个对象的内部数据都已经很好地序列化(例如为每个数据访问加锁)。
如果判断一个类是否线程安全的,
看多个线程同时访问该类中的一个成员变量,是否需要加锁,
可以说,没有线程安全的类,即多线程访问的时候,几乎都需要加锁
下面看例子,
package com.niuli.develop;
public class Test {
public static void main (String [] args) {
Cus c = new Cus();
new Thread(c).start();
new Thread(c).start();
}
}
class Bank{
private int sum = 0;
public void add(int n) {
sum = sum + n;
System.out.println("sum= "+sum);
}
}
class Cus implements Runnable{
Bank b = new Bank();
@Override
public void run() {
for (int i = 0; i < 3; i++) {
b.add(100);
}
}
}
很简单的例子,
首先第一步,找到多线程运行的代码
也就是run方法里面的代码
for (int i = 0; i < 3; i++) {
b.add(100);
}
另外这里用到了Add方法,所以add也算
public void add(int n) {
sum = sum + n;
System.out.println("sum= "+sum);
}
第二步,找到共享数据
Bank b = new Bank();
private int sum = 0;
第三步,明确多线程使用的共享数据.
首先对于数据b就一条语句使用了这个共享变量,因此不会出现线程不安全,但是对于sum,有两条语句使用的,所以就会出现线程安全问题,
解决办法,同步块
Object obj = new Object();
public void add(int n) {
synchronized (obj) {
sum = sum + n;
System.out.println("sum= "+sum);
}
}
或者,给方法加锁
public synchronized void add(int n) {
sum = sum + n;
System.out.println("sum= "+sum);
}
以上就是线程安全的解决办法,同步机制虽然游侠,但是带来了一定的性能损耗,所以,对操作共享数据的部分执行同步,尽量减少这种损耗
线程安全类
在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类:
vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
statck:堆栈类,先进后出
hashtable:就比hashmap多了个线程安全
enumeration:枚举,相当于迭代器
除了这些之外,其他的都是非线程安全的类和接口。
线程安全的类其方法是同步的,每次只能一个访问。是重量级对象,效率较低。