Java 线程同步 synchronized

来源:互联网 发布:mac口红爆款 编辑:程序博客网 时间:2024/05/17 01:40

先来看一个不带线程同步的例子,这个例子很简单,只是让两个线程输出同样的内容,并不做其他的事,所以,线程同步在这里体现的并不明显。

import java.util.Date;public class ThreadTest extends Thread{int pauseTime;String name;/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubThreadTest tT1 = new ThreadTest(1000, "Thread1");tT1.start();ThreadTest tT2 = new ThreadTest(3000, "Thread2");tT2.start();}public ThreadTest(int pauseTime , String name){this.pauseTime = pauseTime;this.name = name;}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();while(true){try {System.out.println(name + ":"+ new Date(System.currentTimeMillis()));Thread.sleep(pauseTime);} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}}}

在来看一个多线程售票的问题,这个例子中体现线程同步的重要性,不保证这一点将会导致错误的执行结果

class TicketSouce implements Runnable{    //票的总数    private int ticket=10;    public void run()    {        for(int i=1;i<50;i++)        {            if(ticket>0)            {                //休眠1s秒中,为了使效果更明显,否则可能出不了效果                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");            }        }    }}public class Test {    public static void main(String args[])    {        TicketSouce mt=new TicketSouce();        //基于火车票创建三个窗口        new Thread(mt,"1").start();        new Thread(mt,"2").start();        new Thread(mt,"3").start();    } } 

输出结果如下图所示:


可以看到,输出的结果并不是我们想要的,所以,需要线程同步的支持


当一个线程要使用火车票这个资源时,我们就交给它一把锁,等它把事情做完后在把锁给另一个要用这个资源的线程。这样就不会出现上述情况。 实现这个锁的功能就需要用到synchronized这个关键字。

synchronized这个关键字有两种用法1、放方法名前形成同步方法;2、放在块前构成同步块。


我们首先用第一种方法实现售票的功能:

代码如下:

class TicketSouce implements Runnable{    //票的总数    private int ticket=10;    public void run()    {        for(int i=1;i<50;i++)        {            try {                //休眠1s秒中,为了使效果更明显,否则可能出不了效果                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            this.sale();        }    }    public synchronized void sale()    {            if(ticket>0)            {                System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");            }    }}public class Test {    public static void main(String args[])    {        TicketSouce mt=new TicketSouce();        //基于火车票创建三个窗口        new Thread(mt,"a").start();        new Thread(mt,"b").start();        new Thread(mt,"c").start();    } } 

第二种同步的方法如下:

class TicketSouce implements Runnable{    //票的总数    private int ticket=10;    public void run()    {        for(int i=1;i<50;i++)        {            synchronized(this){                if(ticket>0)                {                    //休眠1s秒中,为了使效果更明显,否则可能出不了效果                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(Thread.currentThread().getName()+                    "号窗口卖出" + this.ticket-- + "号票");                }                              }        }    }}public class ThreadTest {//主线程    public static void main(String args[])    {        TicketSouce mt=new TicketSouce();        //建立三个线程,同步操作        new Thread(mt,"1").start();        new Thread(mt,"2").start();        new Thread(mt,"3").start();    } } 

两段程序输出的结果如下所示:


可以看到,两段程序都有正确的输出。


注意:同步关键字需要放对地方,否则可能出现不可预料的结果。