• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • YouClaw
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
风吹花落泪如雨
博客园    首页    新随笔    联系   管理    订阅  订阅

JAVA多线程(二)-----线程同步与通信

一、线程同步

1、同步代码块

为了解决并发问题,Java的多线程支持引入同步监视器,使用同步监视器的通用方法就是同步代码块。

//使用obj为同步监视器,任何线程进入下面同步代码块之前
//必须先获得对obj的锁定----其它线程无法获得锁,也就无法修改它
//符合“加锁->修改->释放锁”的逻辑
synchronized(obj){
    ...
    //此处的代码块就是同步代码块
}

2、同步方法

使用synchronized关键字来修改某个方法,称为同步方法。同步方法的同步监视器就是this,也就是调用该方法的对象。

public synchronized void draw(double drawAmount){}

3、同步锁(Lock)

比较常用的ReentrantLock(可重入锁),是Lock的实现类。

class x{
  //定义锁对象
  private final ReentrantLock lock = new ReentrantLock();
  //...
  //需要保证线程安全的方法
  public void m(){
     //加锁
     lock.lock();
     try{
       //..需要保证线程安全的代码
     }finally{
       lock.unlock();
     }
  }
}

4、死锁

当两个线程相互等待对方释放同步监视器时就会发生死锁,Java虚拟机没有检测,也没有采用措施来处理死锁的情况。

 

 

二、线程通信

1、传统的线程通信

 

 Object提供了三个方法:wait(),notify()和notifyAll(),必须由同步监视器调用。

wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()或notifyAll()方法来唤醒该线程。

notify():唤醒在此同步监视器上等待的单个线程。如果所有线程都在此同步监视器上等待,则任意唤醒一个线程。

 

2、使用Condition控制线程通信

当使用Lock对象来保证同步时,Java提供了一个Condition类来保持协调。Lock替代了同步方法或同步代码块,Condition替代了同步监视器的功能。

await():导致当前线程等待,知道其他线程调用该Condition的Signal()方法或signalAll()方法

signal():唤醒在此Lock上的单个线程。若有多个线程在Lock对象上等待,任意唤醒一个。

signalAll():唤醒在此Lock对象上等待的所有线程

//显示定义Lock对象
private final Lock lock = new ReentrantLock();
//获得指定Lock对象对应的Condition
private final Condition cond = lock.newCondition();
int flag = false;
public void X(int a){
  lock.lock();
  try{
     if(!flag){
       cond.await();
     }else{
       //...
       cond.signalAll();
     }finally{
       lock.unlock();
     }
  }
}

 

3、使用阻塞队列(BlockingQueue)控制线程通信

import java.util.concurrent.*;

class Consumer extends Thread{
    private BlockingQueue<String> bq;
    public Consumer(BlockingQueue<String> bq) {
        this.bq = bq;
    }
    public void run() {
        while(true) {
            System.out.println(getName() + "消费者准备消费集合元素!");
            try {
                Thread.sleep(200);
                //尝试取出元素,如果队列已空,则线程被阻塞
                bq.take();
            }catch(Exception ex){
                ex.printStackTrace();
            }
            System.out.println(getName() + "消费完成" + bq);
        }
    }
}
public class Producer extends Thread{
    private BlockingQueue<String> bq;
    public Producer(BlockingQueue<String> bq) {
        this.bq = bq;
    }
    public void run() {
        String[] strArr = new String[]{"Java","Struts","Spring"};
        for(int i = 0; i < 5; i++) {
            System.out.println(getName() + "生产者准备生产集合元素!");
            try {
                Thread.sleep(200);
                //尝试放入元素,如果队列已满,则线程被阻塞
                bq.put(strArr[i%3]);
            }catch(Exception ex){
                ex.printStackTrace();
            }
            System.out.println(getName() + "生产完成" + bq);
        }
    }
    
    public static void main(String[] args) {
        //创建一个容量为1的BockingQueue
        BlockingQueue<String> bq = new ArrayBlockingQueue<>(1);
        new Producer(bq).start();
        new Producer(bq).start();
        new Producer(bq).start();
        new Consumer(bq).start();
    }
}

 

posted @ 2018-08-21 23:10  风吹花落泪如雨  阅读(195)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3