1. synchronized 是一个互斥锁,下面是一个例子
synchronized(对象)
{
需要被同步的代码
}
对象如同锁。持有锁的线程可以在同步中执行。
没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
/*
需求:
银行有一个金库。
有两个储户分别存300员,每次存100,存3次。
*/
class Bank
{
private int sum;
//Object obj = new Object();
public synchronized void add(int n)
{
//synchronized(obj)
//{
sum = sum + n;
try{Thread.sleep(10);}catch(Exception e){}
System.out.println("sum="+sum);
//}
}
}
class Cus implements Runnable
{
private Bank b = new Bank();
public void run()
{
for(int x=0; x<3; x++)
{
b.add(100);
}
}
}
class BankDemo
{
public static void main(String[] args)
{
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
线程t1和线程t2不能同时访问同步代码块的内容,这个很容易理解。这里写的是同步函数,也就相当于同步代码块的对象是this。这个对象是用来标识是哪一个锁。这里就一个锁。若线程进入到同步代码块后,拿到锁,其他线程就不能访问该同步代码块。但其他线程可以访问其他未被分配锁的同步代码块。你如果将代码改成这个
class Bank
{
private int sum;
public void add(int n)
{
synchronized(Thread.currentThread())
{
sum = sum + n;
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+" sum="+sum);
}
}
}
这就相当于没加同步,因为每次一个线程来访问,锁是自己线程对象标识的。当cpu执行权切换时,即使一个线程在执行同步代码块,那么另外一个线程能访问同步代码块,也为2个锁是不同的。
2.经常看见wait() 和notify()
感觉似乎上述解决了安全问题,其实不然,上述线程是在干相同的事情。而当2个线程在对同一资源干不同的事时,会用到wait和notify(唤醒在此对象监视器上等待的单个线程。就是如果在这个锁类调用的wait阻塞的线程就会被唤醒)。
这里是一个资源 ,生产的时候不能消费,消费的时候不能生产。生产一个后就只能消费,不能消费第二个(假定这种简单的情况,),所以只能是一个锁.都是this 锁。这里的设定的flag=true表示有资源了。当没有资源了就会存在while(!flag)中阻塞。还有就是这2个必须在synchronized内部。
3.还有一个就是wait()和notify()谁来调用的问题
这个对象标识锁,所以必须用该对象来调用该方法。否则会
:IllegalMonitorStateException如果当前线程不是此对象监视器的所有者(对象监视器就是锁!)
4.如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。
class ProducerConsumerDemo
{public static void main(String[] args)
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
对于多个生产者和消费者。
为什么要定义while判断标记。
原因:让被唤醒的线程再一次判断标记。
为什么定义notifyAll,
因为需要唤醒对方线程。
因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。
*/
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
// t1 t2
public synchronized void set(String name)
{
while(flag)
try{this.wait();}catch(Exception e){}//t1(放弃资格) t2(获取资格)
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
this.notifyAll();
}
// t3 t4
public synchronized void out()
{
while(!flag)
try{wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格)
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.set("+商品+");
}
}
}
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.out();
}
}
}