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