我的网站:chenmingyu.top/concurrent-…java
进程:操做系统在运行一个程序的时候就会为其建立一个进程(好比一个java程序),进程是资源分配的最小单位,一个进程包含多个线程编程
线程:线程是cpu调度的最小单位,每一个线程拥有各自的计数器,对战和局部变量等属性,而且能过访问共享的内存变量安全
java线程的生命周期总共包括6个阶段:多线程
start()
方法synchronized
修饰的代码块或方法notify()
或notifyAll()
进行唤醒在某一时刻,线程只能处于其中的一个状态并发
线程初始化后,调用start()
方法变为运行状态,调用wait()
,join()
等方法,线程由运行状态变为等待状态,调用notify()
或notifyAll()
等方法,线程由等待状态变成运行状态,超时等待状态就是在等待状态基础上加了时间限制,超过规定时间,自动更改成运行状态,当须要执行同步方法时,若是没有得到锁,这时线程状态就变为阻塞状态,直到获取到锁,变为运行状态,当执行完线程的run()
方法后,线程变为终止状态ide
建立线程有三种方式网站
Thread
类Runnable
接口Callable
接口继承Thread
类this
/** * @author: chenmingyu * @date: 2019/4/8 15:13 * @description: 继承Thread类 */
public class ThreadTest extends Thread{
@Override
public void run() {
IntStream.range(0,10).forEach(i->{
System.out.println(this.getName()+":"+i);
});
}
public static void main(String[] args) {
Thread thread = new ThreadTest();
thread.start();
}
}
复制代码
Runnable
接口/** * @author: chenmingyu * @date: 2019/4/8 15:18 * @description: 实现Runnable接口 */
public class RunnableTest implements Runnable {
@Override
public void run() {
IntStream.range(0,10).forEach(i->{
System.out.println(Thread.currentThread().getName()+":"+i);
});
}
public static void main(String[] args) {
Runnable runnable = new RunnableTest();
new Thread(runnable,"RunnableTest").start();
}
}
复制代码
Callable
接口/** * @author: chenmingyu * @date: 2019/4/8 15:23 * @description: 实现Callable接口 */
public class CallableTest implements Callable<Integer> {
@Override
public Integer call() throws Exception {
IntStream.range(0,10).forEach(i->{
System.out.println(Thread.currentThread().getName()+":"+i);
});
return -1;
}
public static void main(String[] args) throws Exception {
Callable callable = new CallableTest();
FutureTask futureTask = new FutureTask(callable);
new Thread(futureTask,"future").start();
System.out.println("result:"+futureTask.get());
}
}
复制代码
Thread
提供的过时方法能够实现对线程进行暂停suspend()
,恢复resume()
,中止stop()
的操做spa
例:建立一个线程,run()
中循环输出当前时间,在main()
方法中对新建线程进行暂停,恢复,中止的操做操作系统
/** * @author: chenmingyu * @date: 2019/4/8 15:51 * @description: 线程的暂停,恢复,中止 */
public class OperationThread implements Runnable{
@Override
public void run() {
while (true){
try {
TimeUnit.SECONDS.sleep(1L);
System.out.println(Thread.currentThread().getName()+"运行中:"+LocalTime.now());
}catch (InterruptedException e){
System.err.println(e.getMessage());
}
}
}
public static void main(String[] args) throws Exception{
Runnable runnable = new OperationThread();
Thread thread = new Thread(runnable,"operationThread");
/** * 启动,输出当前时间 */
thread.start();
TimeUnit.SECONDS.sleep(3L);
/** * 线程暂停,不在输出当前时间 */
System.out.println("此处暂停:"+LocalTime.now());
thread.suspend();
TimeUnit.SECONDS.sleep(3L);
/** * 线程恢复,继续输出当前时间 */
System.out.println("此处恢复:"+LocalTime.now());
thread.resume();
TimeUnit.SECONDS.sleep(3L);
/** * 线程中止,不在输出当前时间 */
thread.stop();
System.out.println("此处中止:"+LocalTime.now());
TimeUnit.SECONDS.sleep(3L);
}
}
复制代码
输出
由于是过时方法,因此不推荐使用,使用suspend()
方法后,线程不会释放已经占有的资源,就进入睡眠状态,容易引起死锁问题,而使用stop()
方法终结一个线程是不会保证线程的资源正常释放的,可能会致使程序异常
线程安全的暂停,恢复操做可使用等待/通知机制代替
安全的线程暂停,恢复(等待/通知机制)
相关方法:
方法名 | 描述 |
---|---|
notify() | 通知一个在对象上等待的线程,使其重wait()方法中返回,前提是该线程得到了对象的锁 |
notifyAll() | 通知全部等待在该对象上的线程 |
wait() | 调用该方法线程进入等待状态,只有等待另外线程的通知或被中断才会返回,调用该方法会释放对象的锁 |
wait(long) | 超时等待一段时间(毫秒),若是超过期间就返回 |
wait(long,int) | 对于超时时间耕细粒度的控制,能够达到纳秒 |
例:建立一个名为waitThread
的线程,在run()
方法,使用中使用synchronized
进行加锁,以变量flag
为条件进行while
循环,在循环中调用LOCK.wait()
方法,此时会释放对象锁,由main()
方法得到锁,调用LOCK.notify()
方法通知LOCK
对象上等待的waitThread
线程,将其置为阻塞状态,并将变量flag
置为true
,当waitThread
线程再次获取对象锁以后继续执行余下代码
/** * @author: chenmingyu * @date: 2019/4/8 20:00 * @description: wait/notify */
public class WaitNotifyTest {
private static Object LOCK = new Object();
private static Boolean FLAG = Boolean.TRUE;
public static void main(String[] args) throws InterruptedException{
Runnable r = new WaitThread();
new Thread(r,"waitThread").start();
TimeUnit.SECONDS.sleep(1L);
synchronized (LOCK){
System.out.println(Thread.currentThread().getName()+"唤醒waitThread线程:"+LocalTime.now());
/** * 线程状态由等待状态变为阻塞状态 */
LOCK.notify();
/** * 只有当前线程释放对象锁,waitThread获取到LOCK对象的锁以后才会从wait()方法中返回 */
TimeUnit.SECONDS.sleep(2L);
FLAG = Boolean.FALSE;
}
}
public static class WaitThread implements Runnable {
@Override
public void run() {
/** * 加锁 */
synchronized (LOCK){
while (FLAG){
try {
System.out.println(Thread.currentThread().getName()+"运行中:"+LocalTime.now());
/** * 线程状态变为等待状态 */
LOCK.wait();
/** * 再次得到对象锁以后,才会执行 */
System.out.println(Thread.currentThread().getName()+"被唤醒:"+LocalTime.now());
}catch (InterruptedException e){
System.err.println(e.getMessage());
}
}
}
System.out.println(Thread.currentThread().getName()+"即将中止:"+LocalTime.now());
}
}
}
复制代码
输出
mian
线程调用
LOCK.notify()
方法后,沉睡了2s才释放对象锁,
waitThread
线程在得到对象锁以后执行余下代码
线程的安全中止操做是利用线程的中断标识来实现,线程的中断属性表示一个运行中的线程是否被其余线程进行了中断操做,其余线程经过调用该线程的interrupt()
方法对其进行中断操做,而该线程经过检查自身是否被中断来进行响应,当一个线程被中断可使用Thread.interrupted()
方法对当前线程的中断标识位进行复位
例:新建一个线程,run
方法中使用Thread.currentThread().isInterrupted()
是否中断做为判断条件,在主线程中使用thread.interrupt()
方法对子线程进行中断操做,用来达到终止线程的操做,这种方式会让子线程能够去清理资源或一些别的操做,而使用stop()
方法则会会直接终止线程
/** * @author: chenmingyu * @date: 2019/4/8 20:47 * @description: 中断 */
public class InterruptTest {
public static void main(String[] args) throws InterruptedException {
Runnable r = new StopThread();
Thread thread = new Thread(r,"stopThread");
thread.start();
TimeUnit.SECONDS.sleep(1L);
System.out.println(Thread.currentThread().getName()+"对stopThread线程进行中断:"+LocalTime.now());
thread.interrupt();
}
public static class StopThread implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName()+"运行中:"+LocalTime.now());
}
System.out.println(Thread.currentThread().getName()+"中止:"+LocalTime.now());
}
}
}
复制代码
Thread.join()
做用是等待该线程终止
好比在主线程中新建一个子线程,调用子线程的join()
方法,那么在子线程未执行完时,主线程的状态是阻塞状态,只有当子线程执行结束,主线程才会继续往下执行
方法名 | 做用 |
---|---|
join() | 调用A线程的join() 方法后,那么当前线程须要等待A线程终止,才能够继续执行 |
join(long) | 在join() 方法的基础上增长了时间限制(毫秒),超出时间后,不管A线程是否执行完,当前线程都进入就绪状态,从新等待cpu调用 |
join(long,int) | 在join(long) 方法基础上,时间控制上更加严谨,时间细粒度为纳秒(Long毫秒+int纳秒) |
例:循环建立子线程,在main
线程中调用子线程的join()
方法,在子线程中输出了一句日志
/** * @author: chenmingyu * @date: 2019/4/9 20:53 * @description: thread.join(); */
public class JoinThreadTest {
public static void main(String[] args) throws InterruptedException{
IntStream.range(0, 5).forEach(i -> {
try {
Runnable runnable = new JoinThread();
Thread thread = new Thread(runnable,"joinThread");
thread.start();
thread.join();
System.out.println(Thread.currentThread().getName() + "运行中: " + LocalTime.now());
} catch (InterruptedException e) {
System.err.println(e.getMessage());
}
System.out.println("------- 分隔符 ------- ");
});
}
public static class JoinThread implements Runnable {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1L);
System.out.println(Thread.currentThread().getName() + "运行中: " + LocalTime.now());
} catch (InterruptedException e) {
System.err.println(e.getMessage());
}
}
}
}
复制代码
输出
每次循环都是主线程等待子线程终止,在子线程执行完以后主线程才会继续执行
thread.join()源码
调用方线程(调用join方法的线程)执行等待操做,直到被调用的线程(join方法所属的线程)结束,再被唤醒
public final void join() throws InterruptedException {
join(0);
}
复制代码
join(0)
方法
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
复制代码
join()
方法实现等待实际上是调用了wait()
方法,isAlive()
方法的做用是监测子线程是否终止,若是终止或者超过了指定时间,代码就继续往下执行,不然就继续等待,知道条件知足
ThreadLocal
,叫线程变量,是一个以ThreadLocal
对象为键,任意对象为值的存储结构,ThreadLocal
类型的变量在每一个线程中是独立的,在多线程环境下不会相互影响
/** * @author: chenmingyu * @date: 2019/4/10 17:56 * @description: ThreadLocal */
public class ThreadLocalTest {
private static String STATE;
private static ThreadLocal<String> STRING_THREAD_LOCAL = new InheritableThreadLocal<>();
public static void main(String[] args) throws InterruptedException{
STATE = "未重置";
STRING_THREAD_LOCAL.set("未重置");
Thread thread = new Thread(() ->
{
STATE = "已重置";
STRING_THREAD_LOCAL.set("已重置");
System.out.println(Thread.currentThread().getName() + " : 变量已重置");
});
thread.start();
thread.join();
System.out.println(Thread.currentThread().getName() + "STATE : " + STATE);
System.out.println(Thread.currentThread().getName() + "STRING_THREAD_LOCAL : " + STRING_THREAD_LOCAL.get());
}
}
复制代码
输出
ThreadLocal<String>
类型的变量STRING_THREAD_LOCAL
未被子线程修改
参考:java并发编程的艺术