java线程的6种状态以及相互转换

简介: java多线程基础知识,java线程的6种状态以及状态之间的转换

一、线程如何创建

创建线程有三种方式:继承Thread类;无返回值的Runnable;有返回值的Callable

示例如下


package com.rcl.platform.demo;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CreateThread {
    
    public static class TestThread extends Thread {
        @Override
        public void run() {
            System.out.println("--继承thread--");
        }
    }
    
    public static class TestRunnable implements Runnable {

        @Override
        public void run() {
            System.out.println("--runnable没有返回值--");
        }
        
    }
    
    public static class TestCallable implements Callable<String> {

        @Override
        public String call() throws Exception {
            System.out.println("--callable有返回值--");
            return "test-callable";
        }
        
    }
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Thread thread = new Thread(new TestThread());
        thread.start();
        
        thread = new Thread(new TestRunnable());
        thread.start();
        
        FutureTask<String> ft = new FutureTask<>(new TestCallable());  
        thread = new Thread(ft);
        thread.start();
        
        System.out.println(ft.get());
        
        
    }
}

执行结果

--继承thread--
--runnable没有返回值--
--callable有返回值--
test-callable

二、线程相关的方法

screenshot

join示例

package com.rcl.platform.demo;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class JoinTest {
    
    public static class TestThread extends Thread {
        @Override
        public void run() {
            for(int i=0; i<10; i++){
                System.out.println("第" + i + "次执行");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        
        TestThread thread = new TestThread();
        thread.start();
        
        thread.join();
        System.out.println("等待thread执行完毕后main线程结束");
    }
}

join执行结果


第0次执行
第1次执行
第2次执行
第3次执行
第4次执行
第5次执行
第6次执行
第7次执行
第8次执行
第9次执行
等待thread执行完毕后main线程结束

interrupte示例

package com.rcl.platform.demo;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class JoinTest {
    
    public static class TestThread extends Thread {
        @Override
        public void run() {
            for(int i=0; i<1000000000; i++){
                System.out.println("TestThread第" + i + "次执行");
                if(Thread.interrupted()){  
                    return;  
                }
        }
        }
    }
    
    public static class TestThreadSleep extends Thread {
        @Override
        public void run() {
            for(int i=0; i<10; i++){
                System.out.println("TestThreadSleep第" + i + "次执行");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(Thread.interrupted()){  
                    return;  
                }
        }
        }
    }
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        
        TestThread thread = new TestThread();
        thread.start();
        thread.interrupt();
        
        TestThreadSleep threadSleep = new TestThreadSleep();
        threadSleep.start();
        threadSleep.interrupt();
    }
}

interrupt执行结果

TestThread第0次执行
TestThreadSleep第0次执行
java.lang.InterruptedException: sleep interruptedTestThreadSleep第1次执行

    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
    at com.rcl.platform.demo.JoinTest$TestThreadSleep.run(JoinTest.java:27)
TestThreadSleep第2次执行
TestThreadSleep第3次执行
TestThreadSleep第4次执行
TestThreadSleep第5次执行
TestThreadSleep第6次执行
TestThreadSleep第7次执行
TestThreadSleep第8次执行
TestThreadSleep第9次执行

三、锁与monitor
java多线程执行的过程中,为了保证共享变量的线程安全,在多线程对共享变量的访问中需要对共享变量进行加锁操作

加锁的形式主要表现为如下三种形式:同步方法、静态同步方法、同步块。
同步方法锁的是调用该方法的对象,为对象锁
静态同步方法是类锁,锁的是该类的class对象
同步块为对象锁,锁的synchronize中的对象
示例


package com.rcl.platform.demo;

public class ThreadState {
    public static synchronized void read(){
        System.out.println("--这里是类锁--");
    }
    
    public synchronized void write(){
        System.out.println("--这里是对象锁,锁定的是this对象--");
    }
    
    public static void main(String[] args) {
        Object lock = new Object();
        synchronized (lock) {
            System.out.println("--这里是对象锁,锁定的是lock对象--");
        }
    }
}

关于monitor更深层次的讲解参见:http://blog.csdn.net/jingzi123456789/article/details/69951057

四、谈谈volatile
谈到volatile,绕不开的话题还有java内存模型和java编译的重排优化机制

java内存模型
screenshot
内存操作指令
1)lock,作用于主内存变量,把一个变量标记为线程独占。
2)unlock,与lock正相反。
3)read,作用于主内存变量,它把一个变量从主内存传输到工作内存中。
4)load,作用于工作内存变量,把从read里面获取的变量放入工作内存的变量副本中。
5)use,作用于工作内存变量,把变量的值传递给执行引擎。
6)assign,作用于工作内存变量,把执行引擎的值 复制给工作内存变量。同use相反
7)store,作用于工作内存变量,把工作内存变量传输到主内存中。
8)write,作用于主内存变量,把store获取的值,写入到住内存中的变量。

read & load, store & write成对出现
lock & unlock指令来保证代码的原子性。反映到java代码就是synchronized

volatile关键字的作用:
1)用来确保将变量的更新操作通知到其他线程,保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新.当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的.但是volatile 不能保证线程是安全的,因为java里面的运算并非原子操作。
2)volatile还有一个特性就是保证指令不重新排序。现在编译器,为了优化代码,都会重新排序指令。如果在多个线程里面,就会有很大的问题。volatile只能保证局部有序

volatile boolean am= false;
        public void run() {
            context = read();
            write(context);
            am= true;
            say();
            cry();
        }

只能保证1,2在3之前,4、5在3之后

五、ThreadLocal线程本地变量
使用场景:ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了线程保持对象的方法和避免参数传递的方便的对象访问方式
源码分析

//ThreadLocal 中的 set方法,往线程本地变量设置值,实质上值是存储在一个叫ThreadLocalMap中
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

//有此可见,该Map直接存储在Thread本地,与其他线程隔离
void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }

线程本地变量解决不了共享变量问题,只是在线程中开辟了一块空间存储于该线程相关的变量,其他线程无法访问到该线程的本地变量,但是对于变量在线程初始化以前就已经初始化后在绑定到多个线程的线程本地变量中,无法解决共享问题。
示例

package com.rcl.platform.demo;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class ThreadState {
    
    static Map<String, String> map = new HashMap<>();
    
    static class Task1 implements Runnable {
        ThreadLocal< Map<String,String>> threadlocal = new ThreadLocal<>();
        @Override
        public void run() {
            try {
                threadlocal.set(map);
                TimeUnit.SECONDS.sleep(1);
                System.out.println("task1:" + map);
                map.remove("thread1");
                TimeUnit.SECONDS.sleep(1);
                System.out.println("task1:" + map);
                map = new HashMap<>();
                TimeUnit.SECONDS.sleep(1);
                System.out.println("task1:" + map);
            } catch (InterruptedException e) {
            }
        }
    }
    
    static class Task2 implements Runnable {
        ThreadLocal< Map<String,String>> threadlocal = new ThreadLocal<>();
        @Override
        public void run() {
            try {
                threadlocal.set(map);
                TimeUnit.SECONDS.sleep(1);
                System.out.println("task2:" + map);
                TimeUnit.SECONDS.sleep(1);
                System.out.println("task2:" + map);
                TimeUnit.SECONDS.sleep(1);
                System.out.println("task2:" + map);
            } catch (InterruptedException e) {
            }
        }
    }
    
    
    public static void main(String[] args) {
        map.put("thread1", "thread1");
        map.put("thread2", "thread2");
        new Thread(new Task1()).start();
        new Thread(new Task2()).start();
    }
}

运行结果

task2:{thread1=thread1, thread2=thread2}
task1:{thread1=thread1, thread2=thread2}
task2:{thread2=thread2}
task1:{thread2=thread2}
task1:{}
task2:{}

六、线程状态转换
1、java线程有6中状态,分别为NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED详解java.lang.Thread$State枚举类
2、线程初始化为NEW状态,该状态表示还未调用start方法
3、执行线程调用start方法,线程状态转换为RUNNABLE(包括竞争到CPU时间真正意义的执行和没有竞争到CPU时间等待下一个CPU时间的状态)
4、BLOCKED状态为锁竞争,没有竞争到锁为BLOCKED,等待拥有锁的线程释放锁,进入RUNNABLE状态
5、WAITING状态为竞争到锁,执行wait方法,又释放锁,本线程进入WAITING,等待其他线程唤醒notify,notifyall,如果不唤醒,将一直处于WAITING状态
6、TIMED_WAITING为执行sleep join或者有时限的等待
7、线程执行完毕,线程处于TERMINATED状态
线程状态变化
_1

package com.rcl.platform.demo;

import java.util.concurrent.TimeUnit;

public class ThreadState {
    public static void main( String[] args ) throws InterruptedException {
        System.out.println("-------------NEW-------------");
        Thread thread = new Thread();
        System.out.println(thread.getState() + ":" + (thread.getState() == Thread.State.NEW));
        
        System.out.println("-------------分割线-------------");
        
        System.out.println("-------------RUNNABLE、TERMINATED-------------");
        thread = new Thread(new Runnable() {
            public void run() {
                System.out.println(Thread.currentThread().getState() + ":" + (Thread.currentThread().getState() == Thread.State.RUNNABLE));
            }
        });
        thread.start();
        
        TimeUnit.SECONDS.sleep(1);
        System.out.println(thread.getState() + ":" + (thread.getState() == Thread.State.TERMINATED));
        
        System.out.println("-------------分割线-------------");
        
        System.out.println("-------------RUNNABLE、TIMED_WAITING-------------");
        thread = new Thread(new Runnable() {
            public void run() {
                System.out.println(Thread.currentThread().getState() + ":" + (Thread.currentThread().getState() == Thread.State.RUNNABLE));
                System.out.println("sleep 进入 TIMED_WAITING");
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        
        TimeUnit.SECONDS.sleep(1);
        System.out.println(thread.getState() );
        TimeUnit.SECONDS.sleep(2);
        
        System.out.println("-------------分割线-------------");
        
        
        System.out.println("-------------RUNNABLE、TIMED_WAITING-------------");
        final Thread mainThread = Thread.currentThread();
        thread = new Thread(new Runnable() {
            public void run() {
                System.out.println(Thread.currentThread().getState() + ":" + (Thread.currentThread().getState() == Thread.State.RUNNABLE));
                try {
                    System.out.println("join 进入 TIMED_WAITING");
                    System.out.println("mainThread: " + mainThread.getState());
                    TimeUnit.SECONDS.timedJoin(mainThread, 2);//先执行mainthread 
                    System.out.println("mainThread: " + mainThread.getState());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println("testThread: " + thread.getState() );
        
        System.out.println("-------------分割线-------------");
        
        System.out.println("-------------RUNNABLE、WAITING-------------");
        Object lock = new Object();
        final Thread mainThread1 = Thread.currentThread();
        thread = new Thread(new Runnable() {
            public void run() {
                synchronized (lock) {
                    try {
                        System.out.println("wait 进入 WAITING");
                        lock.wait();
                        System.out.println("mainThread1: " + mainThread1.getState() );
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                }
            }
        });
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println("testThread: " + thread.getState() );
        synchronized (lock) {
            lock.notifyAll();
        }
        TimeUnit.SECONDS.sleep(1);
        
        System.out.println("-------------分割线-------------");
        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                synchronized (lock) {
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                }
            }
        });
        thread1.start();
        Thread thread2 = new Thread(new Runnable() {
            public void run() {
                synchronized (lock) {
                    
                }
            }
        });
        thread2.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println("thread2: " + thread2.getState() );
    }
}

执行结果


-------------NEW-------------
NEW:true
-------------分割线-------------
-------------RUNNABLE、TERMINATED-------------
RUNNABLE:true
TERMINATED:true
-------------分割线-------------
-------------RUNNABLE、TIMED_WAITING-------------
RUNNABLE:true
sleep 进入 TIMED_WAITING
TIMED_WAITING
-------------分割线-------------
-------------RUNNABLE、TIMED_WAITING-------------
RUNNABLE:true
join 进入 TIMED_WAITING
mainThread: TIMED_WAITING
testThread: TIMED_WAITING
-------------分割线-------------
-------------RUNNABLE、WAITING-------------
wait 进入 WAITING
mainThread: TIMED_WAITING
testThread: WAITING
mainThread1: TIMED_WAITING
-------------分割线-------------
thread2: BLOCKED

关于多线程,jdk提供了java.util.concurrent包的多线程解决方案,里面包含原子变量,线程安全的Map,Queue等的实现已经线程管理的线程池的实现,正在整理中,敬请期待

相关文章
|
8天前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
65 6
【Java学习】多线程&JUC万字超详解
|
2天前
|
Java 调度 开发者
Java并发编程:深入理解线程池
在Java的世界中,线程池是提升应用性能、实现高效并发处理的关键工具。本文将深入浅出地介绍线程池的核心概念、工作原理以及如何在实际应用中有效利用线程池来优化资源管理和任务调度。通过本文的学习,读者能够掌握线程池的基本使用技巧,并理解其背后的设计哲学。
|
1天前
|
缓存 监控 Java
Java中的并发编程:理解并应用线程池
在Java的并发编程中,线程池是提高应用程序性能的关键工具。本文将深入探讨如何有效利用线程池来管理资源、提升效率和简化代码结构。我们将从基础概念出发,逐步介绍线程池的配置、使用场景以及最佳实践,帮助开发者更好地掌握并发编程的核心技巧。
|
3天前
|
缓存 监控 Java
java中线程池的使用
java中线程池的使用
|
3天前
|
算法 Java 数据处理
Java并发编程:解锁多线程的力量
在Java的世界里,掌握并发编程是提升应用性能和响应能力的关键。本文将深入浅出地探讨如何利用Java的多线程特性来优化程序执行效率,从基础的线程创建到高级的并发工具类使用,带领读者一步步解锁Java并发编程的奥秘。你将学习到如何避免常见的并发陷阱,并实际应用这些知识来解决现实世界的问题。让我们一起开启高效编码的旅程吧!
|
8天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
5天前
|
Java 开发者
Java中的多线程编程基础与实战
【9月更文挑战第6天】本文将通过深入浅出的方式,带领读者了解并掌握Java中的多线程编程。我们将从基础概念出发,逐步深入到代码实践,最后探讨多线程在实际应用中的优势和注意事项。无论你是初学者还是有一定经验的开发者,这篇文章都能让你对Java多线程有更全面的认识。
14 1
|
12天前
|
安全 Java 程序员
Java编程中实现线程安全的策略
【8月更文挑战第31天】在多线程环境下,保证数据一致性和程序的正确运行是每个程序员的挑战。本文将通过浅显易懂的语言和实际代码示例,带你了解并掌握在Java编程中确保线程安全的几种策略。让我们一起探索如何用同步机制、锁和原子变量等工具来保护我们的数据,就像保护自己的眼睛一样重要。
|
12天前
|
安全 Java 开发者
深入浅出Java多线程编程
【8月更文挑战第31天】本文旨在通过浅显易懂的语言和实例,为初学者揭开Java多线程编程的神秘面纱。我们将从基础概念出发,逐步深入到多线程的创建、同步机制及实际应用,帮助读者构建起完整的多线程知识体系。文章不仅包含理论介绍,还提供代码示例,让读者能够动手实践,加深理解。无论你是编程新手还是希望巩固多线程知识的开发者,这篇文章都将是你不可多得的学习资源。
|
11天前
|
Java 调度
Java中的多线程基础与实践
【8月更文挑战第31天】本文将深入浅出地讲解Java中多线程的基础知识,并通过实例展示如何在Java程序中实现多线程。我们将从多线程的基本概念出发,逐步深入到线程的创建、控制以及同步机制,最后通过一个简易版的生产者消费者模型来实践这些知识点。文章旨在帮助初学者快速掌握多线程编程的关键技能,并理解其背后的原理。