多线程卖火车票问题:
public class Demo05 {
public static void main(String[] args) {
newThread 买票12306=new newThread();
newThread 黄牛=new newThread();
newThread 手机APP=new newThread();
买票12306.start();
黄牛.start();
手机APP.start();
}
}
class newThread extends Thread{
private static int 票数=1000;
private Object obj=new Object();
public void run() {
while(true) {
if (票数<=0) {
break;
}
try {
sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
票数-=1;
System.out.println(Thread.currentThread().getName()+" "+票数);
}
}
}
当多个线程同时访问一个数据时,很容易出现问题。为了避免这种情况出现,我们要保证线程同步互斥,就是指并发执行的多个线程,在同一时间内只允许一个线程访问共享数据。
Java中可以使用synchronized关键字来取得一个对象的同步锁。
// Object可以为任何对象,表示当前线程取得该对象的锁。
synchronized (Object) {
}
修改一下上面的案例,在run方法中加入同步锁:
public class Demo05 {
public static void main(String[] args) {
newThread 买票12306=new newThread();
newThread 黄牛=new newThread();
newThread 手机APP=new newThread();
买票12306.start();
黄牛.start();
手机APP.start();
}
}
class newThread extends Thread{
private static int 票数=1000;
private Object obj=new Object();
public void run() {
while(true) {
synchronized(obj) {
if (票数<=0) {
break;
}
try {
sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
票数-=1;
System.out.println(Thread.currentThread().getName()+" "+票数);
}
//让线程放弃CPU资源
Thread.yield();
}
}
}
死锁
同步锁虽好,但也要科学使用,不然就会发生死锁,何为死锁,就是多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。
举个栗子,两个人面对面过独木桥,甲和乙都已经在桥上走了一段距离,即占用了桥的资源,甲如果想通过独木桥的话,乙必须退出桥面让出桥的资源,让甲通过,但是乙不服,为什么让我先退出去,我还想先过去呢,于是就僵持不下,导致谁也过不了桥,这就是死锁。
public class Demo07 {
public static void main(String[] args) {
new Thread() {
private boolean isTrue=true;
@Override
public void run() {
while(true) {
if(isTrue) {
synchronized (LockA.LOCK_A) {
System.out.println("if---LockA");
synchronized (LockB.LOCK_B) {
System.out.println("if---LockB");
}
}
}else {
synchronized (LockB.LOCK_B) {
System.out.println("else---LockB");
synchronized (LockA.LOCK_A) {
System.out.println("else---LockA");
}
}
}
isTrue=!isTrue;
}
}
}.start();
new Thread() {
private boolean isTrue=true;
@Override
public void run() {
while(true) {
if(isTrue) {
synchronized (LockA.LOCK_A) {
System.out.println("if---LockA");
synchronized (LockB.LOCK_B) {
System.out.println("if---LockB");
}
}
}else {
synchronized (LockB.LOCK_B) {
System.out.println("else---LockB");
synchronized (LockA.LOCK_A) {
System.out.println("else---LockA");
}
}
}
isTrue=!isTrue;
}
}
}.start();
}
}
class LockA{
private LockA() {
}
//定义一个常量作为锁对象 不能修改也不能创建
public static final LockA LOCK_A=new LockA();
}
class LockB{
private LockB() {
}
public static final LockB LOCK_B=new LockB();
}
第一个线程锁住了资源1(
A一部分资源),第二个线程锁住了资源2(一部分资源),线程1企图锁住资源2(A让B释放资源,B不放),进入阻塞,线程2企图锁住资源1(B让A释放资源,A不放),进入阻塞,死锁了。
死锁的产生是有规律可循的,只有同时满足以下四个条件,死锁才会产生。
* 1.互斥条件:一个资源每次只能被一个进程使用。独木桥每次只能通过一个人。
* 2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件: 进程已获得的资源,在未使用完之前,不能强行剥夺。
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
知道了死锁产生的必要条件,在开发中就很容易避免死锁问题了。