您的位置:首页 > 其它

线程同步的三种方案

2015-11-20 17:34 267 查看
以电影院售票为例

方案一:同步代码块

public class Cinerma {
int tickets = 50;//剩余票数
Object lock = new Object();//可以看做钥匙对象
//卖票函数
 public void  sellTicket(int num,int id) throws InterruptedException {//本函数一般跑在子线程中,所以在执行tickets = tickets -num;时会发生线程危险

if(tickets>=num){
            System.out.println(Thread.currentThread().getName()+id+":啊哈,有票,让我来跟售票员墨迹一会");//注意此处子线程的id
            Thread.sleep(200);
            System.out.println(Thread.currentThread().getName()+id+":墨迹完了,我要买票了");
            synchronized(lock){//正式买票,同步起来
                
                if(tickets>=num){
                    Thread.sleep(200);
                    tickets = tickets -num;
                    System.out.println(Thread.currentThread().getName()+id+":买了"+num+"张,剩余票数"+tickets);
                }else{
                    System.out.println(Thread.currentThread().getName()+id+":fuck=fuck=fuck=fuck=fuck,刚刚还有票的");
                }
            
            }
        }else{
            System.out.println("没票了咱走吧");
        }
       


方案二:使用加锁对象,ReentrantLock

ReentrantLock reentrantLock = new ReentrantLock();//放在成员里就好
//询问处的函数,一次只能一个线程来问,都排队
public void question(int id) throws InterruptedException{//运行在子线程中的方法
reentrantLock.lock();//此处开始同步
System.out.println(Thread.currentThread().getName()+id+":来买爆米花了");
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName()+id+":买完了");
reentrantLock.unlock();//此处停止同步
}


调用方法:

Cinerma cinerma = new Cinerma();

Thread buyticketThread1 = new BuyTicketThread("情侣", 2, cinerma);//thread的名字,买票数,电影院对象
Thread buyticketThread2 = new BuyTicketThread("单身狗", 1, cinerma);
Thread askThread = new AskQuestionThread("爆米花",cinerma);

buyticketThread1.start();
buyticketThread2.start();
askThread.start();

class BuyTicketThread extends Thread{//买票线程

int num =0;
Cinerma cinerma;
public BuyTicketThread(String name,int num,Cinerma cinerma){
this.num = num;
this.cinerma = cinerma;
this.setName(name);//设置线程名
}

@Override
public void run() {
// TODO Auto-generated method stub
try {
for (int i = 0; i < 1000; i++) {//买1000张票
cinerma.sellTicket(num,i);

}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

public class AskQuestionThread extends Thread{//咨询线程
    
    Cinerma cinerma ;
    String name;
    public AskQuestionThread(String name,Cinerma cinerma){
        this.name = name;
        this.cinerma = cinerma;
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 3; i++) {
            try {
                cinerma.question(i);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
    }

}



方案3:notify()和wake()

建立一个场景,一位母亲有三个孩子,需要给他们做饭,一次只能做一个,每个孩子都要不停的吃饭,做饭和吃饭都需要时间,循环往复

首先建立一个厨房对象,这个对象是最主要的,里面有做饭和吃饭两个方法,重点是,这两个方法都要用synchronized修饰

public class Kitchen {
int food = 0;//剩余的饭
//做饭函数
 public synchronized void cook() throws InterruptedException{//注意这个函数被synchronized给修饰了
if(food>0){//如果当前还有饭

wait();//妈妈线程等待,等待孩子线程notify她,函数会停留在这一句不动,直到有notify
//如果被notify了,则执行下面的
 food = food +1;//做饭
System.out.println("做完饭后一共剩余"+food);
System.out.println(Thread.currentThread().getName()+":饭做好了");
notifyAll();//呼叫孩子线程

}else{//如果当前没剩饭了
food = food +1;
System.out.println(food);
System.out.println(Thread.currentThread().getName()+":饭做好了");
notifyAll();//通知孩子线程

}
<pre name="code" class="java">                System.out.println("通知完孩子后剩余"+food);


}//吃饭函数public synchronized void eat() throws InterruptedException {//在子线程中调用if(food == 0){wait();//孩子线程等待,等妈妈线程唤醒他,此时函数会停留在这一句

//如果这个时候被notify了

food -=1;//吃饭 System.out.println(Thread.currentThread().getName()+"抢到了");notifyAll();//通知她妈没饭了System.out.println(food);}else{food -=1;//吃饭System.out.println(food);System.out.println(Thread.currentThread().getName()+"抢到了");notifyAll();//通知她妈System.out.println(food);}}}


使用四个线程,包含一个妈妈线程三个孩子线程,不停的调用kitchen里的方法,如下

Kitchen kitchen = new Kitchen();
Thread motherThread = new Mother(kitchen);
Thread chilThread1 = new Childrens("大娃", kitchen);
Thread chilThread2 = new Childrens("二娃", kitchen);
Thread chilThread3 = new Childrens("三娃", kitchen);

motherThread.start();
chilThread1.start();
chilThread2.start();
chilThread3.start();

//下面是三个线程的定义
public class Childrens extends Thread{
    Kitchen kitchen;
    public Childrens(String name,Kitchen kitchen){
        this.kitchen = kitchen;
        this.setName(name);
        
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 3; i++) {
            try {
                kitchen.eat();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName()+"吃饱了");
        
        
    }
}
public class Mother extends Thread{
    Kitchen kitchen;
    
    public Mother(Kitchen kitchen){
        this.kitchen = kitchen;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (true) {
            
        
        try {
            kitchen.cook();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: