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(); } }
浙公网安备 33010602011771号