JAVA 多线程——线程竞争

来源:互联网 发布:打开淘宝网首页 编辑:程序博客网 时间:2024/05/16 06:06

下面再来看一个关于线程竞争的例子,记得学过了操作系统课程里对线程的进程做过了一定程度的讲解,但当时对于所谓的同步和互斥方法也并不是很了解。最好的方法还是通过代码来理解

class Acount{    public static int money = 100;    public static void save(int count)    {        money += count;    }    public static void get(int count)    {        money -= count;    }    public static void show()    {        System.out.println(money);    }    public static int getMoney()    {        return money;    }}

首先这里提供了一个银行账号,我们可以通过静态方法来进行取钱、存钱的基本操作。

再来看下面的实现run的接口

class MyRunnable implements Runnable {     private int i = 0;        @Override     public void run()      {        for (i = 0; i < 10; i++)         {            if(Acount.getMoney() > 0)            {               Acount.get(80);            }               Acount.show();            try            {               Thread.sleep(50);            }             catch (InterruptedException e)            {                // TODO Auto-generated catch block               e.printStackTrace();            }               Acount.save(80);               Acount.show();            }       }}

实现了runable的接口的类,提供了对于这个账号的操作方法。
每一次在取钱之前,先判断是否会透支,若透支,则不取钱了。
以下是Main方法

public class Main{    public static void main(String[] args)    {        Thread thread1 = new Thread(new MyRunnable());        Thread thread2 = new Thread(new MyRunnable());        thread1.start();        thread2.start();    }}

有两个账号对其经行操作

-60-6020-6020-6020-6020-60

这是是运行结果,可以看出来在判断在大于80的情况依然取钱了,这是由于是判断钱够不够,再取钱,所以这两个步骤之前有空隙。导致了这一种情况。

  • 利用lock来解决
    这种情况可以利用lock来进行解决,具体代码如下
class  MyRunnable implements Runnable {     private int i = 0;     private static final Lock loc = new ReentrantLock();        @Override     public  void run()      {        loc.lock();        for (i = 0; i < 10; i++)         {            if(Acount.getMoney() > 80)            {               Acount.get(80);               Acount.show();                try                {                   Thread.sleep(50);                }                 catch (InterruptedException e)                {                    // TODO Auto-generated catch block                   e.printStackTrace();                }                   Acount.save(80);                   Acount.show();                }        }        loc.unlock();       }}

几乎是没有什么不同的,知识在run方法中加入了lock的lock()和unLock()方法,来保证一定要执行完这一整套,才让其他的线程来访问这一套方法。

  • synchronized 方法
    对于这个一直把我搞得好糊涂,有时候用synchronized(this)发现不能做到吧{代码}这一块中做到原子访问。后面看别人的博客发现了synchronized(this)是对于对象而言的。
    简而言之 就是synchronized(this)是对于该方法属于的对象而言的,在run()方法中使用synchronized(this)只是会使对于MyRunable的对象进行锁定,而我在main中是使用了两个对象,所以不会起到锁的效果。
    因此应该改成synchronized(lock) 其中lock得是一个静态的属性,若不是静态的属性会发生什么情况?请看下面的代码
class  MyRunnable implements Runnable {     private int i = 0;     private static final Lock loc = new ReentrantLock();     private   Acount asd = new Acount();        @Override     public  void run()      {        synchronized (asd)        {              for (i = 0; i < 10; i++)             {                if(Acount.getMoney() > 80)                {                  System.out.println(Thread.currentThread());                   Acount.get(80);                   Acount.show();                    try                    {                       Thread.sleep(50);                    }                     catch (InterruptedException e)                    {                        // TODO Auto-generated catch block                       e.printStackTrace();                    }                       Acount.save(80);                       Acount.show();                    }                  System.out.println(Thread.currentThread());            }        }     }}

运行之后依然会不同步,这是因为这个对象每一个类的单独有一个。不能保证共享的情况,若把它改成static便可以共享了

0 0
原创粉丝点击