- 什么时候会出现线程安全问题
当多个线程同时访问同一个资源时就有可能出现问题。最终的执行结果和实际上的愿望相违背,或者直接导致程序出错
- 如何解决线程安全问题
基本上所有的并发模式在解决线程安全问题时,都采用了“序列号访问临界资源”的方案。即在同一时刻,只能有一个线程能够访问临界资源,也称作同步互斥访问。
通常来说,在访问临界资源的代码前面加一个锁,当访问结束后释放锁,让其他线程继续访问。
在java中实现了两张方法来实现同步互斥访问 synchronized和lock
- synchronized的使用
互斥锁:能够达到互斥访问的锁。
如果对临界资源加上互斥锁,当一个线程访问临界资源时,其他线程只能等待。
在java中每一个对象都一个锁标记(monitor),也被称为监视器。多线程访问时某个对象时,只有线程获取到了该对象的锁,才能继续访问。
在java中可以直接使用synchronized关键字来标记一段代码或者一个方法。当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。
对于synchronized方法或者synchronized代码块,当代码出现异常时,jvm会自动释放当前线程占用的锁,因此不会因为异常导致死锁。
-
锁方法
public class TestThread {
public static void main(String[] args) {
final InsertData insertData = new InsertData();
new Thread() {
public void run() {
insertData.insert(Thread.currentThread());
};
}.start();
new Thread() {
public void run() {
insertData.insert(Thread.currentThread());
};
}.start();
}
}
class InsertData {
private ArrayList<Integer> arrayList = new ArrayList<Integer>();
public synchronized void insert(Thread thread){
for(int i=0;i<5;i++){
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName()+"在插入数据"+i);
arrayList.add(i);
}
}
}锁住的对象是 insertData ,当创建多个insertData对象分别执行insert方式时,锁就不生效了
-
锁代码块
public class TestThread {
public static void main(String[] args) {
final InsertData insertData = new InsertData();
new Thread() {
public void run() {
insertData.insert(Thread.currentThread());
};
}.start();
new Thread() {
public void run() {
insertData.insert(Thread.currentThread());
};
}.start();
}
}
class InsertData {
private ArrayList<Integer> arrayList = new ArrayList<Integer>();
public void insert(Thread thread){
synchronized(this){
for(int i=0;i<5;i++){
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName()+"在插入数据"+i);
arrayList.add(i);
}
}
}
}和方法锁一样
-
锁静态方法
public class TestThread {
public static void main(String[] args) {
final InsertData insertData = new InsertData();
final InsertData insertData2 = new InsertData();
new Thread() {
public void run() {
insertData.insert(Thread.currentThread());
};
}.start();
new Thread() {
public void run() {
insertData2.insert(Thread.currentThread());
};
}.start();
}
}
class InsertData {
private static ArrayList<Integer> arrayList = new ArrayList<Integer>();
public static synchronized void insert(Thread thread){
for(int i=0;i<5;i++){
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName()+"在插入数据"+i);
arrayList.add(i);
}
}
}锁住的类,同一个类的对象都被锁住