线程的同步和死锁
同步问题引出
当多个线程访问同一资源时,会出现不同步问题。比如当票贩子A(线程A)已经通过了“判断”,但由于网络延迟,暂未修改票数的间隔时间内,票贩子B(线程B)也通过了“判断”。此时,若票数只剩下了最后一张,则会出现两个线程同时通过判断并最终会修改票数,出现错误(票数为0或-1)。
线程同步处理
解决同步问题的关键是锁,指的是当某一个线程执行操作的时候,其它线程外面等待。
现这把锁的功能,就可以使用 synchronized
关键字来实现,利用此关键字可以定义同步方法或同步代码块, 在同步代码块的操作里面的代码只允许一个线程执行。
1. 同步代码块
synchronized(同步对象){
同步代码操作;
}
一般要进行同步对象处理的时候可以采用当前对象 this
进行同步。
卖票范例(同步代码块版):
class MyThread implements Runnable { // 线程的主体类
private int ticket = 5;
@Override
public void run() { // 线程的主体方法
while(true) {
synchronized(this) { // 每一次只允许一个线程进行访问
if (this.ticket > 0) {
try {
Thread.sleep(100); // 模拟网络延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买票,ticket = " + this.ticket --);
} else {
System.out.println("-----票已售完-----");
break;
}
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
}
}
结果:
票贩子A买票,ticket = 5
票贩子C买票,ticket = 4
票贩子C买票,ticket = 3
票贩子C买票,ticket = 2
票贩子B买票,ticket = 1
-----票已售完-----
-----票已售完-----
-----票已售完-----
加入同步处理之后,程序的整体的性能下降了。同步实际上会造成性能的降低。
2. 同步方法
只需要在方法定义上使用synchronized 关键字即可。
class MyThread implements Runnable { // 线程的主体类
private int ticket = 5;
public synchronized boolean sale() { // 每一次只允许一个线程进行访问该方法
if (this.ticket > 0) {
try {
Thread.sleep(100); // 模拟网络延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买票,ticket = " + this.ticket --);
return true;
} else {
System.out.println("-----票已售完-----");
return false;
}
}
@Override
public void run() {
while(this.sale()) {}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
}
}
结果:
票贩子A买票,ticket = 5
票贩子A买票,ticket = 4
票贩子A买票,ticket = 3
票贩子C买票,ticket = 2
票贩子C买票,ticket = 1
-----票已售完-----
-----票已售完-----
-----票已售完-----
在日后学习 Java 类库的时候会发现,系统中许多的类上使用的同步处理采用的都是同步方法。
线程死锁
死锁是在进行多线程同步的处理之中有可能产生的一种问题,所谓的死锁指的是若干个线程彼此互相等待的状态。
若干个线程访问同一资源时一定要进行同步处理,而过多的同步会造成死锁。