《Java多线程编程核心技术_高洪岩 著》读后整理01
写在前面:零零散散地花了不少时间在这本书上,看到第四章的时候实在是有些坚持不下去,但出于对作者的尊重还是硬着头皮在昨天晚上拜读完了,看完的感想就简单几个字‘我从未见过如此****之人和出版社’,不知为什么会有人推荐这本书估计多半是出版社的广告帖。
毕竟花了不少时间在这上边,得对时间负责,在此整理于2017年5月16日。
注意:若有幸被他人查阅,请以辩证的眼光对待,若有问题不必在此指出。
第1章 Java多线程技能
概念
-
线程可以理解成是在进程中独立运行的子任务。
-
CPU在这些任务之间不停地切换,由于切换的速度非常快,给使用者的感受就是这些任务似乎在同时运行。
-
单任务的特点就是排队执行,也就是同步,就像在cmd中输入一条命令后,必须等待这条命令执行完才可以执行下一条命令一样。
-
线程被调用的时机是随机的
-
一个进程正在运行时至少会有一个线程在运行
-
Thread.java类中的start()方法通知“线程规划器”此纯种已经准备就绪,等待调用线程对象的run()方法。这个过程其实就是让系统安排线程,具有异步执行的效果。如果调用代码thread.run()就不是异步执行了,而是同步,那么此线程对象并不交给“线程规划器”来进行处理,而是由main主线程来调用run()方法,也就是必须等run()方法中的代码执行完后才可以执行后面的代码。
-
执行star()方法的顺序不代表线程启动的顺序。
mythread.start();//代码肉眼看到的前后顺序不代码线程的启动顺序
* 构造函数Thread(Runnable target)不光可以传入Runable接口的对象,还可以传入一个Thread类的对象,还可以传入一个Thread类的对象,这样做完全可以将一个Thread对象中的run()方法交由其他的线程进行调用。
* 自定义线程类中的实例变量针对其它线程可以有共享与不共享之分,这在多个线程之间进行交互时是很重要的一个技术点。
* 在某些JVM中,i--的操作要分成如下3步:
* ```
1)取得原有i值。
2)计算i-1。
3)对i进行赋值
-
非线程安全主要是指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改、值不同步的情况,进而影响程序的执行流程。
-
虽然println()方法在内部是同步的,但i-- 的操作却是在进入pringln()之前发生的。
基本方法
-
currentThread()方法可返回代码段正在被哪个线程调用的信息。
Thread.currentThread().getName();//线程名
* run()方法是自动调用的方法。
* isAlive()方法是判断当前的线程是否处于活动状态。活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的。
* ```
mythread.isAlive();//是否为活动状态
-
sleep()方法的作用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行)。这个“正在执行的线程”是指this.currentThread()返回的线程。
Thread.sleep(1000);//throws InterruptedException
* getId()方法的作用是取得线程的唯一标识。
* ```
Thread.currentThread().getId();//获取线程id值,long类型
-
yield()方法的作用是放弃当前CPU资源,将它让给其它的任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。
Thread.yiled();//native方法
* 在操作系统中,线程可以划分优先级,优先级较高的线程得到的CPU资源较多,也就是CPU优先级较高的线程对象中的任务。高优先级的线程总是大部分先执行完,但不代表高优先级的线程全部先执行,线程的优先级具有一定的规则性,也就是CPU***尽量***将执行资源让给优先级较高的线程。不要把线程的优先级与运行结果的顺序作为衡量的标准,优先级较高的线程不一定每一次都先执行完run()方法中的任务,也就是说,线程优先级与打印顺序无关,不要将这两者的关系相关联,它们的关系具有不确定性和随机性。
* ```
mythread.getPriority();//获得优先级
mythread.setPriority(MAX_PRIORITY);//设置优先级
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
停止线程
-
停止线程:调用interrupt()方法仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程,而且好像是子线程调用并没有用。
-
Thread.java类里提供了两种判断线程是不是停止状态的:
1)public static boolen interrupter(): 测试当前线程是否已经是中断状态,执行后具有将状态标志清除为false的功能。 2)public boolean isInterrupter(): 测试线程是否已经是中断状态,但不清除状态标志。
* 停止线程:异常法
* ```
@Override
public void run() {
if (this.interrupter()){//主线程
//TODO 业务逻辑
thorw new InterrupterException();
}
}
-
使用stop()方法停止纯种则是非常暴力的,感觉像是线程直接被kill掉。
-
暂停线程:suspend(), resume(),使用不当易造成同步对象独占,使其它线程无法访问公共同步对象,也容易出现因为线程暂停而导致数据不同步的情况。
mythread.suspend();//暂停线程 //TODO something mythread.resume();// 恢复线程
---
##### 守护线程
* 守护线程是一种特殊的线程,它的特性有陪伴的含义,当进程中不存在非守护线程了,则守护线程自动销毁。
* 典型的守护线程就是垃圾回收线程,当进程中不存在非守护线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。
* 守护线程的作用是为其他线程的运行提供便利服务,最典型的应用就是GC,它就是一个很称职的守护者。
* ```
//Thread 类
public class MyThread extends Thread {
private int i = 0;
@Override
public void run() {
try {
while (true) {
i++;
System.out.println("i=" + i);
Thread.sleep(1000);
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
try {
MyThread mt = new MyThread();
mt.setDaemon(true);//把mt这个线程设置为守护线程
mt.start();
Thread.sleep(5000);
/*
*‘最后一行代码’执行完后此例中并没有其它非守护线程,
*所以mt做为守护线程的任务也跟着结束了
*/
System.out.println("此例中的所有线程结束");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}