码迷,mamicode.com
首页 > 其他好文 > 详细

SyncThread用法

时间:2016-05-07 11:25:21      阅读:647      评论:0      收藏:0      [点我收藏+]

标签:

在多线程程序中,难免会多个线程操纵一个共享变量,以模拟多个窗口共同售票为例:
public class Demo {
    private int num=10;
    //未加synchronized修饰的sell方法
    public synchronized void sell(){
        if(num==0){
            return;
        }
        num--;
        System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+num+"张");
    }
    class window implements Runnable{

        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(true){
                sell();
                try {
                    Thread.sleep(1000*2);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        
    }
    public static void main(String[] args) {
        Demo d = new Demo();
        window w = d.new window();
        new Thread(w,"窗口1").start();
        new Thread(w,"窗口2").start();
        new Thread(w,"窗口3").start();
        new Thread(w,"窗口4").start();
        
    }

输出结果:

窗口1卖出一张票,剩余6张
窗口4卖出一张票,剩余7张
窗口3卖出一张票,剩余8张
窗口2卖出一张票,剩余5张
窗口4卖出一张票,剩余3张
窗口3卖出一张票,剩余3张
窗口1卖出一张票,剩余4张
窗口4卖出一张票,剩余1张
窗口1卖出一张票,剩余0张
窗口2卖出一张票,剩余1张
窗口3卖出一张票,剩余1张

很明显这不是我们想要的结果 导致这种结果的原因就是没有对sell方法加锁造成的

举个例子,int i=10; 开启两个进程 进程1和进程2 同时执行i=i-1操作并输出,

假设进程1先开始运行

进程1运行过程中,首先会先把i读取到内存当中,然后cpu从内存中读取i,执行i-1,最后将结果i=9刷新到内存中. 在整个过程中,某一时间段(cpu进行计算后,将结果返回内存前)存在两个i值,即内存中i=10 cpu中i=9;

这个时候若进程2读取i的值,读取的是内存中i的值 10,并不是进程1操作了i的结果值 9,因为此时进程1还未将计算结果刷新到内存;这便导致了明明执行了两次i-1操作结果却i=9;


为了避免这种情况,我们要对sell方法加锁(synchronized)

打个比方,一群人(多线程)去参观一座庄园(一个实体类的对象),里面有很多房子(方法),有的房子有锁(加了synchronized关键字),有的无锁(未加synchronized关键字),无锁的房子可随意由大家参观,而有锁的房子在门口放了把钥匙,当有人(进程)想进入房间(执行该方法),他首先会用钥匙打开房门然后带着钥匙进入房间,这样便不会有人进去打扰他参观,当他参观完后 走出房间将钥匙放在外面留给下一个想要参观的人(需要执行该方法的其他进程).

如此便避免了多个线程对共享资源操作发生冲突

让我们看一下synchronized修饰了方法之后的运行结果

    //加了synchronized修饰的sell方法
    public synchronized void sell(){
        if(num==0){
            return;
        }
        num--;
        System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+num+"张");
    }
运行结果:

窗口1卖出一张票,剩余9张
窗口4卖出一张票,剩余8张
窗口3卖出一张票,剩余7张
窗口2卖出一张票,剩余6张
窗口3卖出一张票,剩余5张
窗口2卖出一张票,剩余4张
窗口4卖出一张票,剩余3张
窗口1卖出一张票,剩余2张
窗口4卖出一张票,剩余1张
窗口2卖出一张票,剩余0张

这才是我们想要的结果;


synchronized如果用来修饰方法,作用范围则是调用这个方法的对象 若按照下述方法开启进程 则依然是错误的结果
<pre name="code" class="java">public static void main(String[] args) {
		Demo d = new Demo();
		new Thread(d.new window(),"窗口1").start();
		new Thread(d.new window(),"窗口2").start();
		new Thread(d.new window(),"窗口3").start();
		new Thread(d.new window(),"窗口4").start();
		
	}

原因便是在开启线程时 每一次都new了一个window对象,这相当于是四个对象的四个进程,有四把锁,所以这样开启线程加不加synchronized修饰方法都是一样的

SyncThread用法

标签:

原文地址:http://blog.csdn.net/qq_28701323/article/details/51331035

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!