七、多线程

一、线程概述

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

二、线程的创建和启动

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 线程的生命周期

  • 新建状态:new了一个线程之后
  • 就绪状态:调用了start之后(永远不要直接调用run方法)
  • 运行状态:线程获得CPU,开始运行run方法之后
  • 阻塞状态:调用sleep,调用阻塞式IO方法,等待通知,程序调用了suspend方法等,都会使线程进入阻塞状态。
  • 线程死亡:run()执行完毕,抛出未捕获的Exception和Error,或者调用该程序的stop()方法来结束该线程。

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

4 控制线程

4.1 join线程

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

  • join()
  • join(long millis)
  • join(long millis,int nanos)

4.2 后台线程

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

4.3 线程睡眠Sleep

  • Thread.sleep(long millis)
  • Thread.sleep(long millis, int nanos)

4.4 线程让步yield

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

  • Thread.yield

4.5 改变线程优先级

  • Thread.setPriority(int newPriority)
    优先级值在1~10之间,也可以使用MAX_PRIORITY(10),MIN_PRIORITY(1),NORM_PRIORITY(5)

5 线程的同步

5.1同步代码块

synchronized(obj){ 同步代码块 }

5.2同步方法

public synchronized void draw(double drawAmount)

5.3释放同步监视器的锁定

以下情况会释放:

  • 代码块执行完毕
  • break return
  • 抛出错误或者异常
  • 程序执行了同步监视器对象的wait()方法

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()三个方法,必须由同步监视器来调用:

  • 对于使用synchronized修饰的同步方法,该类的默认实例this就是同步监视器
  • 对于使用synchronized修饰的代码块,后面括号里的对象就是同步监视器

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

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

  • await()
  • signal()
  • signalAll()
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。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容