一、定义及关键字
多个线程共同访问同一个资源,进行的协调工作。
关键字:sychronized
示例程序:
创建了3个线程,共享同一个对象(资源)t,如果不对资源上锁的话,运行结果就会出现结果的情况,当线程访问t时,线程2也会访问这是num的值就会错误。希望的结果是每有一个线程访问资源时,num+1.
public class testSync implements Runnable{ Timer time=new Timer(); public static void main(String args[]){ testSync t=new testSync(); Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); t1.setName("t1"); t2.setName("t2"); t3.setName("t3"); t1.start(); t2.start(); t3.start(); } @Override public void run() { // TODO Auto-generated method stub time.add(Thread.currentThread().getName()); } } class Timer{ public int num=0; public void add(String s){ //synchronized(this){ num++; System.out.println(s+"是第"+num+"个线程"); try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
多次运行结果为:
1.
t1是第2个线程
t3是第3个线程
t2是第2个线程2.
t3是第3个线程
t1是第3个线程
t2是第3个线程对资源上锁后的运行结果为:
1.
t2是第1个线程
t3是第2个线程
t1是第3个线程
2.t1是第1个线程
t3是第2个线程
t2是第3个线程
分析结果:当一个线程访问资源时,同时就拿到了该资源的锁,将其锁定,也就是在这期间,其他线程无法对资源操作,也就没办法更改num的值,只有这个线程执行完了,把锁释放掉,其他线程才能访问。
二、死锁
线程T1和线程T2都需要访问资源r1和r2,并且T1锁住了r1,T2锁住了r2,那么 T1和T2都无法进行下去,形成死锁。
他public class testDeadLock implements Runnable{ int flag=0; static Object o1=new Object(); static Object o2=new Object(); @Override public void run() { // TODO Auto-generated method stub if(flag==0){ synchronized(o1){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized(o2){}; }; } if(flag==1){ synchronized(o2){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } synchronized(o1){}; } public static void main(String args[]){ testDeadLock t=new testDeadLock(); Thread t1=new Thread(t); t.flag=1; Thread t2=new Thread(t); t1.start(); t2.start(); } }
分析:创建了两个线程t1和t2,两个线程共享两个静态对象o1和o2,但两个if语句,使t1锁住o1等待o2,t2锁住o2等待o1,陷入死锁。
三、生产者消费者
生产者消费者也是一个进程同步问题
public class ProdecerConsumer {
public static void main(String args[]){
syncStack s=new syncStack();
Producer p=new Producer(s);
Consumer c=new Consumer(s);
new Thread(p).start();
new Thread(c).start();
}
}
class ManTou{
int id;
ManTou(int id){
this.id=id;
}
}
//用栈模拟筐子
class syncStack{
int index=0;
ManTou[] arrMantou=new ManTou[6] ;
public synchronized void push (ManTou mantou) throws ArrayIndexOutOfBoundsException
{
if(index>arrMantou.length)
{
try {
this.wait();//锁定当前对象的线程wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.notify();
}
arrMantou[index]=mantou;
index++;
}
public synchronized ManTou put() throws ArrayIndexOutOfBoundsException
{
index--;
if(index<0){
try {
this.wait();
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.notify();
}
return arrMantou[index];
}
}
class Producer implements Runnable{
syncStack s;
//确定扔到那个筐里
Producer(syncStack s){
this.s=s;
}
@Override
public void run()
{
// TODO Auto-generated method stub
for(int i=0;i<20;i++){
ManTou mm=new ManTou(i);
s.push(mm);
System.out.println("生产了第:"+s.index+"个馒头");
}
}
}
class Consumer implements Runnable{
syncStack ss;
Consumer(syncStack ss){
this.ss=ss;
}
@Override
public void run()
{
// TODO Auto-generated method stub
for(int i=0;i<20;i++){
ss.put();
System.out.println("消费了第:"+ss.index+"个馒头");
}
}
}
put和push中的两个锁用来锁定index,为了防止放进去一个馒头指针还未来得及++就有放了一个馒头。
总结:需要上锁的就是代码不能间隔,需要连续执行的。