Java多线程

第1章 多线程背景知识介绍
在程序设计语言中没有哪一种特性如线程一般矛盾。一方面可以简化模型,编写强大的代码,另一方面会因为考虑不周而面临bug
1.进程:是程序或任务的执行的过程,具有动态性,它持有资源(共享内存,共享文件)和线程
2.线程:是系统中最小的执行单元,同一进程中有多个线程。线程共享线程的资源
3.线程交互:即线程通信
4.线程之间存在同步和互斥
第2章 Java 线程初体验
2-1 Java 中线程的常用方法介绍
Java实现线程的两种主要方法:
①.继承Thread类
②.实现Runnable接口
但是二者都必须重写public void run()方法
这里写图片描述
sleep(long millis, int nanos) 线程休眠 millis休眠的时间,单位是毫秒,可以精确到纳秒
join(long millis, int nanos) 调用线程 可以让其它线程等待自己运行,直到结束
static void yield() 当前运行线程释放处理器资源并且重新去竞争处理器资源
static Thread currentThread() 返回当前正在处理器上运行的线程的引用
重载的几个形式
1.没有参数,指明了其它的线程一定要等待正在执行的线程执行完毕之后,都会获得运行的机会
2.nanos是要把精确度改变,可改成纳秒
2-2 隋唐演义框架说明
多线程创建概况
相互独立的线程的创建。
使用Runnable接口两个线程
隋唐演义三个对象:军队-ArmyRunnable;英雄人物-KeyPersonThread;舞台-Stage
2-3 隋唐演义实战开发—演员简介
1:创建线程的方法有两种

1-1:继承Thread类

1-2:实现Runnable接口

2:线程中的方法比较有特点,比如:启动(start)、休眠(sleep)、停止等,多个线程是交互执行的(CUP在某个时刻

只能执行一个线程,当一个线程休眠了或者执行完毕了,另一个线程才能占用CPU来执行),因为这是CPU的结构来决

定的,在某个时刻CUP只能执行一个线程,不过速度相当快,对于人来讲可以认为是并行执行的。

在一个.java文件中,可以有多个类,但只能有一个public类。

这两种创建线程的方法本身没有什么不同,一个是实现Runnable接口,一个是继承Thread类。而使用实现Runnable接口这种方法:1.可以避免Java的单继承的特性带来的局限性;2.适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码及数据有效分离,较好地体现了面向对象的设计思想。开发中大多情况下都使用实现Runnable接口这种方法创建线程。

实现Runnable接口创建的线程最终还是要通过将自身实例作为参数传递给Thread然后执行
语法:Thread Actress = new Thread(Runnable target, String name)
例如:Thread actressThread=new Thread(new Actress(),“Ms.Runnable”);
actressThread.start();
}}
2-4 隋唐演义实战开发—军队
1.加入join是为了让舞台线程最后停止,如果不加有可能舞台线程结束,军队线程还未停止,就好比导演喊停,演员还在演!可以在join后面加入测试语句System.out.println(“舞台结束!”);,然后去掉或者保留join观察效果。

2.volatile 关键字 保证了线程可以正确地读取其他线程写入的值,如果不写成volatile,由于可见性的问题,当前线程有可能不能读到这个值//可见性JMM(JAVA内存模型)happens-before原则、可见性原则
用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的值
3.Thread.yield();//让出处理器时间,公平竞争,是指当前线程让出处理,允许下一个线程占用处理器的时间执行。
这里写图片描述
2-5 隋唐演义实战开发—关键先生
Thread中start()方法,join()方法,sleep()方法,volatite作用

Java Thread中,start()方法,等其他代码(Thread.join()和Thread.sleep()除外)执行完后再执行它。

Java Thread中, join()方法主要是让调用该方法的thread完成run方法里面的东西后, 再执行join()方法后面的代码。
join方法可中断其它线程的执行,等待调用join方法的线程结束,即使是主线程main也会被中断
join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
Java Thread中, sleep()方法主要是让调用该方法的thread完成run方法里面的东西后且等待休眠的时候结束(唤醒), 再执行sleep()方法后面的代码。

一. volatite 简述
Java 语言提供了一种稍弱的同步机制,即 volatile 变量.用来确保将变量的更新操作通知到其他线程,保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新. 当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的.

二. volatite 线程安全?
volatile 变量对所有线程是立即可见的,对 volatile 变量所有的写操作都能立即反应到

其他线程之中,换句话说:volatile 变量在各个线程中是一致的,所以基于 volatile 变量的运算是线程安全的。这句话论据貌似没有错,论点确实错的.
public class KeyPersonThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+“开始了战斗…”);
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+“左突右杀,攻击隋军…”);
}
syso…“结束了战斗!”;
}
}

/**
*隋唐演义大舞台
*/
public class Stage extends Thread {
@Override
public void run() {

System.out.println(“正当双方杀得正High,半路杀出了个程咬金!”);

Thread mrChen=new KeyPersonThread();
mrChen.setName(“程咬金”);

//停止军队作战
//停止线程的方法
armyTaskOfSuiDynasty.keepRunning=false;
armyTaskOfRevolt.keepRunning=false;

try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}

/**

  • 历史大戏留给关键人物
    */
    mrChen.start();

//万众瞩目,所有线程等待程先生完成历史使命
try {
mrChen.join();//对象是mrChen
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}

System.out.println(“谢谢观看隋唐演义,再见!”);

}

Ps:Thread.currentThread()表示静态意思。
第3章 Java 线程的正确停止
3-1 错误的方法—stop
stop方法使得线程戛然而止,完成了什么工作,哪些工作还没有做,都不知道,且清理工作也没有做,所以不是正确的停止线程方法
正确的停止线程方法是,在线程执行中设置状态标识,通过控制标识来控制线程正常完整的执行结束线程
volatile是保证所有子线程里的变量都能同步到主内存里变量的值
不要用stop()方法结束线程
3-2 正确的方法—设置退出旗标
在线程中,停止线程的方法:设置旗标
使用volatile 定义boolean running=true,通过设置标志变量running,来结束线程。
如本文:volatile boolean keepRunning=true;
这样做的好处是:使得线程有机会使得一个完整的业务步骤被完整地执行,在执行完业务步骤后有充分的时间去做代码的清理工作,使得线程代码在实际中更安全
这里写图片描述
3-3 广为流传的错误方法—interrupt方法
interrupt()–初衷并不是用于停止线程
在调用sleep()或者join()的时候,一旦其他线程调用interrupt(),它将会收到一个异常,这些被阻塞的线程因为某些原因需要被唤醒,比如外部发生了中断而需要响应,这时就采用抛出异常的方式来使其作出响应。总而言之,interrupt()方法并不能正确地停止进程
一个线程在阻塞状态下(例如sleep),此时interrupt的话,将会产生两个结果:
1、进程的interrupt状态被清除(cleard)而非被设置(set)。
2、sleep方法会抛出异常。
第4章 线程交互
线程停止:
1、调用stop()方法会使线程戛然停止,而无法知道线程任务完成情况,官方已经不推荐使用。
2、interrupt()方法设置线程的标识位,并在线程中判断标志位的状态,从而结束线程,但是当在线程中开启了另外的线程时,比如在线程中Tread.sleep(),这时候调用interrupt()方法设置标志位可能设置的是你想要停止的线程,也可能是想要停止的线程中的线程的标志位,因此interrupt()方法也并不能很好的结束线程。
3、第三种方法,在线程的类声明一个volatile变量来记录线程的状态,相当于interrupt()方法那样,volatile关键字表示线程中的变量可以接受外部其他线程改变。因此可以在需要停止的地方设置volatile声明的变量的值设置为状态,并在执行run()函数里判断是否结束。
System.out.print();-------------格式化输出
①.%d-----------输出整数
②.%10.2f-------输出一个浮点数,小数点前有10位,小数点后为2位
③.%n-----------换行

@Java线程——线程交互——争用条件
1、当多个线程同时共享访问同一数据(内存区域)时,每个线程都尝试操作该数据,从而导致数据被破坏(corrupted),这种现象称为争用条件
2、原因是,每个线程在操作数据时,会先将数据初值读【取到自己获得的内存中】,然后在内存中进行运算后,重新赋值到数据。
3、争用条件:线程1在还【未重新将值赋回去时】,线程1阻塞,线程2开始访问该数据,然后进行了修改,之后被阻塞的线程1再获得资源,而将之前计算的值覆盖掉线程2所修改的值,就出现了数据丢失情况
这里写图片描述

@Java线程——线程交互——互斥与同步
一、互斥
1、同一时间,只能有一个线程访问数据
二、同步
1、是一种通信机制,一个线程操作完成后,以某种方式通知其他线程
三、实现方法
1、【互斥】构建锁对象(Object objLock),通过synchronized(lockObj){ 互斥的代码块 }
synchronized关键字实现互斥行为,既可以出现在方法体之上也可以出现在方法体内,以一种块的形式出现。
然后通过lockObject的wait方法(注意:wait的线程被存放在wait set 中)和notifyAll方法实现同步。
2、加锁操作会开销系统资源,降低效率。
3、在某线程的条件不满足任务时,使用lockObj.wait()对线程进行阻挡,防止其继续竞争CPU资源,滞留在wait set中,等待唤醒,【唤醒后继续完成业务】
4、【同步】在某一代码正确执行完业务后,通过lockObj.notifyAll()唤醒所有在lockObj对象等待的线程
步骤:
1.互斥:同一时间,只能有一个线程访问数据
2.同步:通信机制;一个线程完成,以某种方式通知其他线程
3.锁的概念:private final Object lockObj = new Object();
4.互斥实现方式:synchronized关键字
synchronized(lockObj){—执行代码----}加锁操作
lockObj.wait();线程等待状态,以避免线程持续申请锁,不去竞争cpu资源
lockObj.notifyAll();唤醒所有lockObj对象上等待的线程

1:线程的互斥是指,在同一时间关键数据只能有一个线程访问
2:线程互斥的实现有synchronized关键字来实现,类似于给对应的代码加锁,只有获得锁的线程才能运行此段代码
3:线程的同步是指,线程间的一种通信控制,一个线程完成了某事后通知另一个线程可以进行下面的事情了
4:线程同的实现有wait(),notify(),notifyall()这几个方法来实现,这几个方法都是属于object类,并不是thread类

建议:
1、Java Memory Mode:JMM描述了java线程如何通过内存进行交互,了解happens-before,synchronized,voliatile & final
2、Locks % Condition:锁机制和等待条件的高层实现 java.util,concurrent.locks
3、线程安全性:原子性与可见性,死锁等

4、多线程常用的交互模型
· Producer-Consumer模型
· Read-Write Lock模型
· Future模型
· Worker Thread模型
5、Java5中并发编程工具:java.util.concurrent 线程池ExcutorService Callable&Future BlockingQueue
6、推荐书本:CoreJava & JavaConcurrency In Practice

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值