七、多线程

2016-10-30  本文已影响0人  柳岸

一、线程概述

线程是在程序中独立并发的执行流,相比于进程,线程具有更高的性能,多个线程可以共享一个进程虚拟空间,线程之间共享内存非常方便,可以拥有很高的并发。

二、线程的创建和启动

2.1 继承Thread类创建线程类

通过继承Thread类来创建启动多线程的步骤如下:
(1)定义Thread的子类,重写run方法
(2)创建Thread子类的实例
(3)通过start来启动线程
Thread.currentThread()可以返回当前正在执行的线程对象
getName()可以返回线程的名字

public class FirstThread extends Thread{
    public void run()
    {...}
}
new FirstThread().start();

2.2 实现Runnable接口创建线程类

通过Runnable接口来创建并启动多线程的步骤如下:
(1)定义Runnable的实现类,并且重写run方法
(2)创建Runnable实现类的实例,并且以此实例作为Thread的target来创建Thread对象

public class SecondThread implements Runnable
{
    public void run()
    {...}
}
new Thread(st,'name').start();

采用Runnable接口的方式来创建的多条线程可以共享线程类的实例属性。
采用Runnable接口方式来创建的线程只能通过Thread.currentThread()来获取当前线程,而不能通过this

3 线程的生命周期

可以通过线程的isAlive方法来判断线程是否死亡
不要试图对一个已经死亡的线程调用start方法

4 控制线程

4.1 join线程

某个线程调用另一个线程的join方法以后,该线程将被阻塞,直到被join的线程执行完毕以后为止。

4.2 后台线程

后台线程有个特征:如果前台线程都死亡,则后台线程会自动死亡。
通过调用Thread的setDaemon(true)的时候,就可以将其设为后台线程。
可以通过isDaemon()来判断是否是后台线程

4.3 线程睡眠Sleep

4.4 线程让步yield

yield方法不会阻塞该线程,而是转入就绪状态,让线程调度器重新调度一次。

4.5 改变线程优先级

5 线程的同步

5.1同步代码块

synchronized(obj){ 同步代码块 }

5.2同步方法

public synchronized void draw(double drawAmount)

5.3释放同步监视器的锁定

以下情况会释放:

5.4 同步锁

常用的有可重用锁ReentrantLock,可重用的意思是说,对已经加锁的ReentrantLock可以再次上锁,该对象会维持一个计数器来记录。

public class Accout
{
    private final ReetrantLock lock = new ReentrantLock();
    public void draw(double drawAmout)
    {
        lock.lock();
        try
        {
        //临界区
        }
        finally
        {
            lock.unlock();
        }
    }
}

5.5 死锁

当两个线程相互等待对方释放同步监视器就会发生死锁。

6 线程通信

6.1 线程的协调运行

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

6.2 使用条件变量进行控制协调

如果程序不使用synchronized关键字来保持同步,而是直接使用Lock对象来保持同步,则系统中不存在隐式的同步监视器对象。Java提供了一个Condition类来保持协调。

public class Account
{
    private final Lock lock = new ReentrantLock();
    private final Condition cond = lock.newCondition();

####6.3 使用管道流
如果两条线程之间需要更多的信息交互,则可以考虑使用管道流。

PipedWriter pw = null;
PipedReader pr = null;
try
{
pw = new PipedWriter();
pr = new PipedReader();
pw.connect(pr);
new WriterThread(pw).start();
new ReaderThread(pr).start();
}

###7 Callable和Future
Callable看起来像是Runnable的接口和增强版,call方法是其线程执行体,但是比run()方法更强大:可以有返回值,可以抛出异常

class RtnThread implements Callable<Integer>
{
public Integer call(){
return i
}
}
public class CallableTest
{
public static void main(String[] args)
{
RtnThread rt = new RtnThread();
FutrueTask<Integer> task = new FutureTask<Integer>(rt);
new Thread(task,'name').start();
System.out.println(task.get());
}
}


###8 线程池
略过

###9 线程相关类
####9.1 ThreadLocal类
ThreadLocal类是线程局部变量的意思,就是为每一个使用该变量的线程都提供一个变量值的副本。从而避免冲突。
ThreadLocal提供了三个public方法:
* T get()
* void remove()
* void set(T value)
>如果需要进行多个线程之间的资源共享,就需要使用同步机制,如果只是需要隔离多个线程之间的共享冲突,则可以使用ThreadLocal

####9.2 线程包装不安全的集合
Java集合中介绍的ArrayList,LinkedList, HashSet, TreeSet, HashMap都是线性不安全的。可以使用Collections的方法来将其变成线程安全:
SynchronizedCollection/List/Map/Set/SortedMap/SortedSet

####9.3 线程安全的集合类
JDK1.5开始,java.util.concurrent包下提供了ConcurrentHashMap, ConcurrentLinkedQueue。
上一篇 下一篇

猜你喜欢

热点阅读