java线程的同步与死锁
线程的同步与死锁
不同步操作的唯一好处:处理速度快(多个线程并发执行)。举例:网络转账和去柜台转账。但是这是对数据访问的不安全操作。
每一个线程对象操作时的轮番抢占资源的问题。
一、线程的同步处理
举个粗俗一点的例子就是——上厕所。假如只有一个厕所,每次上厕所的过程就是:一个人进入之后,把门锁上,过一会儿之后,出来,下一个人进入。如果第一个人没出来,就要在外面等待。
同步指的是所有的线程不是一起进入到方法中执行,而是按照顺序一个一个的执行。
在有一个线程执行的时候,该操作对外是“锁”住的,以至于能够让其他线程发现该操作是“锁”着的状态,而进入等待。那么怎么实现“锁”的操作呢?
可以采用synchronized关键字来处理。有两种模式:同步代码块、同步方法。
- 同步代码块(是在进入到方法中拦截,进入到方法中的线程可能依然有很多个。)
class MyThread implements Runnable{
private int cat=200;
@Override
public void run() {
for (int x=0;x<200;x++) {
//在同一时刻,只允许一个线程进入并且操作,其他线程要等待
synchronized (this) {//表示为程序逻辑上锁
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(this.cat>0) {
System.out.println(Thread.currentThread().getName()+",cat="+this.cat--);
}
}
}
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread p=new MyThread();
new Thread(p,"主人A").start();
new Thread(p,"主人B").start();
new Thread(p,"主人C").start();
}
}
- 同步方法(对整个方法拦截)
class MyThread implements Runnable{
private int cat=300;
@Override
public void run() {
for (int x=0;x<2000;x++) {
this.feed();
}
}
public synchronized void feed() {
if(this.cat>0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(this.cat>0) {
System.out.println(Thread.currentThread().getName()+",cat="+this.cat--);
}
}
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread p=new MyThread();
new Thread(p,"主人A").start();
new Thread(p,"主人B").start();
new Thread(p,"主人C").start();
}
}
同步虽然可以保证数据的完整性(线程安全操作),但是执行的速度会很慢。
二、死锁
同步会带来最大的问题就是死锁。如果其他相关的几个线程都在等待,就会造成死锁。
死锁一旦出现,整个程序就会终止执行。
一定要记住:数据要想完整操作就必须使用同步,但是过多的同步就会出现死锁。