Java多线程

标签 :java基础


1. Java多线程的实现

(1)继承Thread类,重写run方法。
(2)实现Runnable接口,重写run方法。(这个设计比较好)
本质上Thread类就是实现了Runable的类。

// 创建线程
Runnable task = new TaskClass();
// 开启线程
new Thread(task).start();

2. 线程池使用

使用ExecutorService类和Executors类实现线程池,代码如下:

// 固定线程数的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 按需创建新线程的线程池
ExecutorService executor2 = Executors.newCachedThreadPool();
// 使用线程池
executor.execute(new TaskClass());
// 关闭线程池
executor.shutdown();

3. 线程同步问题

(1)竞争状态问题:多个线程以冲突的方式访问一个公共资源
(2)线程安全的类:该类的对象在多线程下没有导致竞争状态问题。
线程安全、不安全的类就是指这种公共资源类

4. 解决线程同步问题

(1)给临界区方法加synchonized关键字。
  一个线程访问这个方法时,整个对象锁住,其他线程访问这个对象的任意方法会阻塞,直到解锁。
(2)给需要同步的语句包上synchronized语句块。
  好处是只需要锁住导致线程不安全的语句,而不是锁住整个方法。

synchronized(obj){
    doSomething();
}

(3)显式使用锁。
  实现了Lock接口的对象是一个锁对象。可以利用锁对象对其他对象显式加锁。例如ReentrantLock类,可以创建具有公平策略的锁,即那个线程先来那个先得。(默认不是公平锁)
  使用方法,在需要实现同步访问的类中,组合一个Lock接口的实例,在临界区前调用lock.lock(),在结束后调用lock.unlock()。如下:

public void add(int a){
    lock.lock();
    try{
        // 临界区
        doSomething();
    }
    catch(InterruptedException e){
    }
    finally{
        lock.unlock();
    }
    // 写try-catch这个习惯比较好,保证锁能释放
}

  ReentrantLock类可以创建condition,比synchronzied关键字更灵活可控。
 

5. 线程间合作

(1)使用Condition接口的实例。Condition接口的实例从Lock对象生成,使用时必须获得该Condition的锁(否则抛出异常)。使用方法是把Condition的实例放在Lock实例的他同一个类底下。

// 创建条件
private static Condition condition = lock.newCondition();
// 阻塞当前线程,直到别人来唤醒
condition.await();
// 唤醒所有阻塞线程
condtition.signalAll();

(2)传统方法,监视器。即使用每个对象本身的wait(),notify(),notifyAll()等方法。

6. 生产者/消费者模型

(1)使用一个lock,两个condition(notEmpty和notFull),每次生产/消费时用lock锁住Buffer。
(2)如果生产时发现容器已满,需要等待notFull条件;
(3)同样,如果消费时发现容器为空,则需要等待notEmpty条件。
(4)每次生产完唤醒等待notEmpty条件的线程,每次消费完唤醒等待notFull条件的线程。

posted @ 2017-04-10 21:17  斑鱼  阅读(126)  评论(0编辑  收藏  举报