一、多线程的安全问题
- 为什么会出现安全问题?
- 因为程序在运行时,会出现一个线程在判断条件满足后,具备了执行资格,但没有运行代码
- 后一个线程也判断了条件,也具备了执行资格,后一个线程运行了代码,但这时候,线程运行的条件不满足了
- 这时候,就出现了安全问题
- 2.问题的原因?
- 当多条语句在操作同一线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完
- 另一个线程参与进来,导致 共享数据错误
- 解决办法
- 对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其它线程不参与执行。
二、同步代码块
即有synchronized关键字修饰的语句块。
被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
代码如:
synchronized(object){
}
注:同步是一种高开销的操作,因此应该尽量减少同步的内容。
通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。
/**
* 线程同步的运用
*
* @author XIEHEJUN
*
*/
public class SynchronizedThread {
class Bank {
private int account = 100;
public int getAccount() {
return account;
}
/**
* 用同步方法实现
*
* @param money
*/
public synchronized void save(int money) {
account += money;
}
/**
* 用同步代码块实现
*
* @param money
*/
public void save1(int money) {
synchronized (this) {
account += money;
}
}
}
class NewThread implements Runnable {
private Bank bank;
public NewThread(Bank bank) {
this.bank = bank;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
// bank.save1(10);
bank.save(10);
System.out.println(i + "账户余额为:" + bank.getAccount());
}
}
}
/**
* 建立线程,调用内部类
*/
public void useThread() {
Bank bank = new Bank();
NewThread new_thread = new NewThread(bank);
System.out.println("线程1");
Thread thread1 = new Thread(new_thread);
thread1.start();
System.out.println("线程2");
Thread thread2 = new Thread(new_thread);
thread2.start();
}
public static void main(String[] args) {
SynchronizedThread st = new SynchronizedThread();
st.useThread();
}
}
三、同步方法
即有synchronized关键字修饰的方法。
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,
内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
代码如:
public synchronized void save(){}
注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类
四、死锁问题
1、什么是死锁:
在编写多线程的时候,必须要注意资源的使用问题,如果两个或多个线程分别拥有不同的资源,
而同时又需要对方释放资源才能继续运行时,就会发生死锁。
简单来说:死锁就是当一个或多个进程都在等待系统资源,而资源本身又被占用时,所产生的一种状态。
2、造成死锁的原因:
多个线程竞争共享资源,由于资源被占用,资源不足或进程推进顺序不当等原因造成线程处于永久阻塞状态,从而引发死锁
3、当然死锁的产生是必须要满足一些特定条件的:
(1)互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放;
(2)请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
(3)不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
(4)循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。
/**
* 用两个线程请求被对方占用的资源,实现线程死锁
*/
public class DeadLockThread implements Runnable {
private static final Object objectA = new Object();
private static final Object objectB = new Object();
private boolean flag;
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println("当前线程 为:" + threadName + "\tflag = " + flag);
if (flag) {
synchronized (objectA) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(threadName + "已进入同步代码块objectA,准备进入objectB");
synchronized (objectB) {
System.out.println(threadName + "已经进入同步代码块objectB");
}
}
} else {
synchronized (objectB) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(threadName + "已进入同步代码块objectB,准备进入objectA");
synchronized (objectA) {
System.out.println(threadName + "已经进入同步代码块objectA");
}
}
}
}
public static void main(String[] args) {
DeadLockThread deadlock1 = new DeadLockThread();
DeadLockThread deadlock2 = new DeadLockThread();
deadlock1.flag = true;
deadlock2.flag = false;
Thread thread1 = new Thread(deadlock1);
Thread thread2 = new Thread(deadlock2);
thread1.start();
thread2.start();
}
}