原CSDN博客已弃用,文章会逐渐迁移过来。

转帖请注明本文出自weimeig的博客(http://blog.csdn.net/weimeig/article/details/79512965),请尊重他人的辛勤劳动成果,谢谢

应朋友们反馈的JAVA基础薄弱的问题,决定出一套完整的JAVA基础教程,帮助大家复习,巩固JAVA基础,今天要讲的是多线程的经典案例。

卖票问题

class Xc implements Runnable{  

public int chepiao = 100;  
    public void run(){  
        while (true) {  
            if(chepiao>0){  
                System.out.println("第" + Thread.currentThread().getName() + "个车站正在卖出第" + (101-chepiao) + "张车票");  
                --chepiao;  
            }else{  
                break;  
            }  
        }  
    }  
}  
public class XianCheng {  
    public static void main(String [] args){  
        Thread Xc1 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源  
        Xc1.start();  
        Thread Xc2 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源  
        Xc2.start();  
    }  
}  

通过代码,我们不难发现,在运行的过程中出现了错误,因为Xc1和Xc2各自都生成了100张车票,而车票没有共享,此时,我们需要将车票定义为静态变量,使得两线程在竞争售票的过程中,共享车票,于是,将常量定义为静态常量,用static修饰:

public static int chepiao = 100;  

class Xc implements Runnable{  

public static int chepiao = 100;  
    public void run(){  
        while (true) {  
            if(chepiao>0){  
                System.out.println("第" + Thread.currentThread().getName() + "个车站正在卖出第" + (101-chepiao) + "张车票");  
                --chepiao;  
            }else{  
                break;  
            }  
        }  
    }  
}  
public class XianCheng {  
    public static void main(String [] args){  
        Thread Xc1 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源  
        Xc1.start();  
        Thread Xc2 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源  
        Xc2.start();  
    }  
}  

但是很快的,我们又发现了新问题,因为线程在竞争的过程中,CPU的切换是非常快的,可能线程1正好执行完–maipiao的时候,线程已经切换到了线程2,此时–maipiao又再执行了一次,导致跳过了一张票没有卖出,或者,当线程1恰好正好将要执行–maipiao但还没执行的时候,线程已经切换到了线程2,此时因为线程1并没有进行–maipiao操作,线程2卖出了重复的同一张票以后,才执行了–maipiao,导致出现了同一张票重复销售的情况。

此时,我们需要引入线程锁的概念,以解决线程的同步问题。

第一种写法:

class Xc implements Runnable{  
    public static int chepiao = 100;  
    //synchronized的作用是,让它所管辖的代码部分,要么全部执行完,要么全部不执行,synchronized既可修饰代码块,又可以修饰函数  
//  如果是锁整个方法,可以在方法内加锁,表达上比如public synchronized void run(){,但对于此案例,是两个线程之间竞争售票,因此不适宜锁起来整个方法  
    //如果synchronized是锁起来整个方法的,synchronized修饰函数不需要传入字符串参数,相当于默认是this  
    public void run(){  
        while (true) {  
            synchronized (" ") {//在需要加锁保证完整运行的代码块旁边加上synchronized (" "){}包裹代码,即可锁起来该部分代码,()内的字符串随意定义  
                if(chepiao>0){  
                    System.out.println("第" + Thread.currentThread().getName() + "个车站正在卖出第" + (101-chepiao) + "张车票");  
                    --chepiao;  
                }else{  
                    break;  
                }  
            }  
        }  
    }  
}  
public class XianCheng {  
    public static void main(String [] args){  
        Thread Xc1 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源  
        Xc1.start();  
        Thread Xc2 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源  
        Xc2.start();  
    }  
}  

第二种写法:

class Xc implements Runnable{  
    public static int chepiao = 100;  
    public static String str = new String("weimeig");//提取出来提高可维护性,同时定义为static静态变量,使得str是公共的  
                            //如果不定义成static静态,则两个线程各自有各自的str,那么大家竞争的就不是同一个资源  
    public void run(){  
        while (true) {  
            synchronized (str) {//若不定义为static静态,则两个线程的str是线程自己的,而不是公共的,因为这种写法,初始化的str写在了锁的外面  
                if(chepiao>0){  
                    System.out.println("第" + Thread.currentThread().getName() + "个车站正在卖出第" + (101-chepiao) + "张车票");  
                    --chepiao;  
                }else{  
                    break;  
                }  
            }  
        }  
    }  
}  
public class XianCheng {  
    public static void main(String [] args){  
        Thread Xc1 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源  
        Xc1.start();  
        Thread Xc2 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源  
        Xc2.start();  
    }  
}