java学习笔记——synchronized的理解(仅供参考)

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.如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。

InterruptedException 



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();
}
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值