《实战java高并发程序设计》笔记(二)
2020-02-16 本文已影响0人
MikeShine
写在前面
上一章中,对于并发编程的一些基础的概念进行了一定的了解。
这一章我们来具体的线程基本操作
第二章 Java并行程序基础
第二章 线程基本操作1. 线程的基本操作
- 线程:进程是线程的容器,线程是轻量级的进程,是程序最小的执行单位,使用多线程而不是多进程,是因为线程间调度成本远远小于进程。
- 新建线程:通过new关键字创建一个线程对象,然后调用这个对象的 start() 方法即可。(注意,如果直接调用 run()方法,那就只是一个方法调用,而不是创建线程。)
创建线程的方法:继承 Thread类 / 实现 Runnable 接口 / 实现 Callable 接口
关于前两种的说明在 java进阶课程(一)中已经有了相关说明。
而对于实现 Callable 接口,是实现 call() 方法,并且有返回值。
Callable callable = new MyThreadCallable(); // callable 实现类独享
FutureTask task = new FutureTask(callable); // FutureTask 封装该对象
new Thread(task).start(); // FutureTask 对象创建线程
- 终止线程:stop() 方法可以终止,但是可能引起数据不一致性,已经废弃,不推荐使用。
- 线程中断: interrupt() 中断线程,设置中断标志位;isInterrupted() 方法判断当前线程是否被中断(通过标志位);interrupted() 方法是静态方法,判断是否中断,并清除标志位。
书上介绍了一下,要有中断,同时也要在 run() 方法中增加相应的中断处理代码。
还用代码例子,说明在 sleep() 时候被中断,要重新设置中断标志位。
-
等待和通知:wait() & nofity() 方法在 Object 类中(不是 Thread 类的方法)。在调用 wait() 方法后,线程在 这个对象上等待,同时线程被放入这个对象的等待池中。而 notify() 方法会随机唤醒一个该对象等待池中的线程。nofityAll() 全部唤醒。这两个方法都必须包含在 synchronized 中,都要先获得对象监视器。
-
wait() & sleep() 的区别:wait() 可以被唤醒;执行时释放锁。sleep() 则不是
-
挂起和继续执行:suspend() 方法挂起线程,不释放任何资源;resume() 使得线程继续。这两个方法会造成死锁,没发解决,已经废弃不推荐使用。
-
等待线程结束:join() 方法阻塞在当前线程,直到目标线程执行结束。(用于一个线程需要另外一个线程的输出的情况。)join() 方法是通过 wait() 方法来实现的。
-
谦让:线程让出CPU资源,重新加入下一次竞争。
2. Volatile 与 java 模型
之前说过, Volatile 关键字可以保证可见性,但是并不一定可以保证原子性。
3. 线程组
- 线程组:多个具有相同功能的线程放在一起,就是一个线程组。可以使用 Thread 的构造函数,指定线程所属的线程组。
ThreadGroup gp = new ThreadGroup();
Thread t1 = new Thread(gp, new ThreadGroupName(), "T1");
- activeCount():其获取活动线程的总数是一个估值
- list():显示线程组的详细信息。
4. 守护线程
- 守护线程就是后台线程,当只有后台线程时候, JVM 就会自动退出
- 垃圾回收 和 JIT都可以理解为守护线程
5. 线程安全 & Synchronized
- Synchronized 的作用:线程同步,加锁,使得每次只有一个线程进入同步代码块,保证线程的安全性。
- 指定加锁对象:对给定的对象加锁,进入同步代码前要获得指定对象的锁。
- 直接作用于实例对象:对当前实例加锁。获得实例的锁才能进入
- 直接作用于静态方法:对当前类的加锁,获得类的锁才能进入。