读书人

五分钟让你彻底了解JAVA多线程

发布时间: 2013-02-24 17:58:56 作者: rapoo

5分钟让你彻底了解JAVA多线程
/** * 模拟火车售票场景。成员变量total表示火车表总量。showToal()一旦被执行就开始卖表(total-1),票没了(当total的值小于等于零)就停止卖票 * @author 许井龙 * */public class SynchronizedDemo implements Runnable {/* 火车票总量*/private static int total = 100;/** * 程序入口 * @param args */public static void main(String[] args) {//模拟八个售票窗口 Thread td1 = new Thread(new SynchronizedDemo()); Thread td2 = new Thread(new SynchronizedDemo()); Thread td3 = new Thread(new SynchronizedDemo()); Thread td4 = new Thread(new SynchronizedDemo()); Thread td5 = new Thread(new SynchronizedDemo()); Thread td6 = new Thread(new SynchronizedDemo()); Thread td7 = new Thread(new SynchronizedDemo()); Thread td8 = new Thread(new SynchronizedDemo()); //八个售票窗口同时售票; td1.start(); td2.start(); td3.start(); td4.start(); td5.start(); td6.start(); td7.start(); td8.start();}@Override/** * 多线程执行入口 */public void run() {//售票:稍后会有不同的具体实现showToal();}}?如果showToal()代码如下,

?

?

public  void  showToal(){//long sTime = System.currentTimeMillis();while(true){//当总量(total)当小于等于0的时候,就不能在继续减少了if(total>0){            try {              //模拟线程阻塞1ms                Thread.sleep(1);              } catch (Exception e) {                  e.printStackTrace();              }            total = total - 1;            System.out.println(Thread.currentThread().getName() + "  余票: " + total  + "张"); }else{//反之结束程序break;}}//System.out.println(Thread.currentThread().getName() + "耗时:" + (System.currentTimeMillis() - sTime)/1000);}
?执行结果如下,

?

?

....Thread-4  余票: 5张Thread-1  余票: 4张Thread-0  余票: 3张Thread-3  余票: 0张Thread-5  余票: 1张Thread-2  余票: 2张Thread-7  余票: -1张Thread-1  余票: -2张Thread-6  余票: -3张Thread-4  余票: -4张
?余票居然出现了负数,显然是我们程序出现了漏洞。聪明的你马上就意识到,showTota()没有使用synchronized。因此你修改了showTota(),

?

?

public synchronized void  showToal(){//long sTime = System.currentTimeMillis();while(true){// 当总量(total)当小于等于0的时候,就不能在继续减少了if(total>0){            try {                //模拟线程阻塞1ms                Thread.sleep(1);              } catch (Exception e) {                  e.printStackTrace();              }            total = total - 1;            System.out.println(Thread.currentThread().getName() + "  余票: " + total  + "张"); //反之结束程序}else{break;}}//System.out.println(Thread.currentThread().getName() + "耗时:" + (System.currentTimeMillis() - sTime)/1000);}
??但是我们看看运行结果,

?

?

Thread-5  余票: 4张Thread-2  余票: 4张Thread-4  余票: 6张Thread-6  余票: 6张Thread-3  余票: 6张Thread-0  余票: 2张Thread-7  余票: 2张Thread-4  余票: -3张Thread-1  余票: -4张Thread-2  余票: -4张Thread-3  余票: -3张Thread-5  余票: -3张Thread-6  余票: -3张Thread-0  余票: -6张Thread-7  余票: -6张
?似乎和你预期的不太一样哦。那么是synchronized没生效?还是我们使用的不对呢?现在我告诉你:showToal()需要声明为static。public synchronized static void showToal(){//long sTime = System.currentTimeMillis();while(true){if(total>0){ try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } total = total - 1; System.out.println(Thread.currentThread().getName() + " 余票: " + total + "张"); }else{break;}}//System.out.println(Thread.currentThread().getName() + "耗时:" + (System.currentTimeMillis() - sTime)/1000);}?我们再来看看执行结果,

?

?

们再来看看执行结果,Thread-0 total = 14Thread-0 total = 13Thread-0 total = 12....Thread-0 total = 11Thread-0 total = 10Thread-0 total = 9Thread-0 total = 8Thread-0 total = 7Thread-0 total = 6Thread-0 total = 5Thread-0 total = 4Thread-0 total = 3Thread-0 total = 2Thread-0 total = 1Thread-0 total = 0Thread-0耗时:0Thread-7耗时:0Thread-6耗时:0Thread-5耗时:0Thread-4耗时:0Thread-3耗时:0Thread-2耗时:0Thread-1耗时:0
?没有出现负数的余票,我们的目标达到了。那一定会问为什么我在非static方法使用synchronized不生效呢?这就涉及到了线程同步锁的问题。
?

第二个场景,我们寄希望于是用synchronized解决上述问题,但是由于showTotal()非static,因此及时使用了synchronized,也是各自对象加各自的锁。达不到控制并发的目的。如图,


五分钟让你彻底了解JAVA多线程
?

第三个场景,通过synchronized和static双重约束,我们发现total不再出现负数,因为showTotal被声明为static后,内存中也只有一份,因此其线程锁也是唯一的,这样就很好的控制了线程并发。


五分钟让你彻底了解JAVA多线程
?

通过“线程同步锁”的讲解,我们发现控制并发是有先决条件的,

1、在同一个JVM内;

2、操作同一资源的线程,其线程锁要一致;

使用多线程需要注意的事项

实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

我们思考下,是否可以使用synchronized和static双重约束的方法控制数据库并发呢??

答案是否定的,通过三个场景在JVM中的剖析图,我们可以清楚的发现,synchronized和static双重约束的方法的上下文为单个JVM,超过了这个范围他就力不从心了。所以如果要控制数据库的并发,还要使用数据库的技术,正所谓术业有专攻。

?

许井龙 于腊月二十四

?

读书人网 >编程

热点推荐