初识多线程

多线程学习

  • 什么是线程
  • Java多线程的使用

什么是线程

这里先引用一下百度给出的概念java

线程是系统可以进行运算调度的最小单位。他被包含在进程只中,是进程中的实际运做单位。算法

这里只摘取简单的引用,便于通俗的理解,毕竟百度百科上面的东西太过于专业化,专业名词太多。shell

上面有一个名词进程,这里解释一下进程微信

通常咱们打开一个软件,好比qq,微信,这个时候就启动了一个进程,在Windows任务管理器中咱们能够看到它们 进程 红框部分就是一个进程多线程

好了咱们大概算是通俗的理解了什么是进程 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。jvm

这里用一个简单的例子演示一下ide

public class test1 {

    private static class ther extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    TimeUnit.MICROSECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("启动了一个线程");
            }
        }
    }

    public static void main(String[] args)  {
        ther ther = new ther();
        ther.start();
        for (int i = 0; i < 10; i++) {
            try {
                TimeUnit.MICROSECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("主函数执行了");
        }
    }
}

咱们看一下执行结果,暂时不要理会如今的写法函数

主函数执行了
启动了一个线程
主函数执行了
启动了一个线程
主函数执行了
启动了一个线程
启动了一个线程
主函数执行了
主函数执行了
启动了一个线程
主函数执行了
启动了一个线程
主函数执行了
启动了一个线程
主函数执行了
启动了一个线程
启动了一个线程
主函数执行了
主函数执行了
启动了一个线程

咱们能够看见它是交替运行的 平时咱们的代码都是串行的,也就是顺序执行,而如今这钟状况就是并行的状态,这就是线程一个比较直观的概念学习

Java多线程的使用

线程的建立

这里列举几种线程经常使用的几种方式spa

经过继承Thread而后实现它的run()方法来进行建立线程

private static class exThread extends Thread{
        @Override
        public void run() {
            System.out.println("继承thread实现run方法建立线程");
        }
    }

经过实现Runnable建立一个线程

private static class impRunnable implements Runnable{
        @Override
        public void run() {
            System.out.println("经过实现Runnable建立一个线程");
        }
    }

经过实现Callable建立一个线程,这种建立方式是有返回池的

private static class impCallable implements Callable{
        @Override
        public Object call() throws Exception {
            System.out.println("经过实现Callable建立一个线程,它是有放回值的");
            return "ssuccess";
        }
    }

线程的启动

这里列举5钟启动线程的方式

public static void main(String[] args) {
        new exThread().start();//经过直接建立对象而后调用start();方法启动一个线程
        new Thread(new exThread()).start();//经过new一个线程类而后传入须要启动的线程,而后调用线程类的start方法启动
        new Thread(()->{
            System.out.println("lambda表达式建立并启动一个线程");
        }).start();
        Thread thread = new Thread(new FutureTask<String>(new impCallable()));
        thread.start();//经过newThread传入FutureTask启动
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(()->{
            System.out.println("线程池启动并建立");
        });
        executorService.shutdown();//中止
    }

执行结果以下

继承thread实现run方法建立线程
继承thread实现run方法建立线程
lambda表达式建立并启动一个线程
经过实现Callable建立一个线程,它是有放回值的
线程池启动并建立

稍微总结一下: 线程经常使用的建立并启动的方式有两种 1.经过new Thread().start(); 2.经过new Thread(Runnable).start(); 还有一种是使用线程池,不过本质上仍是使用上面的两种方式 固然你也可使用lambda表达式,本质上没什么区别写法不一样而已

线程的方法

sleep线程休眠

这个方法颇有意思,好比说,你可在你的代码某些业务中加个线程休眠5分钟,而后老板说你这个程序太慢了,你就能够说加钱调优,还能按照百分比调整程序的运行速度。是否是很实用? 开个玩笑,开个玩笑 咱们来看下使用方式

public static void main(String[] args) {
        testSleep();
    }
    static void  testSleep(){
        new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我先睡一会");
        }).start();
    }

执行结果咱们能够看出它过了一会才执行 线程休眠之后何时醒过来,根据sleep里的参数决定,时间到了就醒了 线程休眠通俗理解:就是当前我不运行了,别的线程照样能够运行

Yield方法,翻译过来是让步的意思

咱们先来看一下用法而后在来解释一下含义

static void testYield(){
        new Thread(()->{
            for (int i=0;i<100;i++){
                System.out.println("A----"+i);
                if (i%10==0){
                    Thread.yield();
                }
            }
        }).start();;

        new Thread(()->{
            for (int i=0;i<100;i++){
                System.out.println("B----"+i);
                if (i%10==0){
                    Thread.yield();
                }
            }
        }).start();;
    }

这里就不演示打印结果了,不是颇有表明性 讲一下这个方法的做用

一个线程在执行过程当中假如调用yieid这个方法,当前线程会先中止下来进入等待队列,这也就是让步的意思,可是当回到等待队列之后,在系统的调度算法里,它依然有可能把刚回到等待队列的线程继续执行,固然更大的可能性仍是先执行以前等待队列的线程,因此yieid的意思是,我虽然让出了,可是能不能抢到执行机会我无论。

join方法,也就是加入的意思

先看写法

Thread thread2 = new Thread(() -> {
            System.out.println("thread1执行了一下,如今到我执行了");
        });

        Thread thread1 = new Thread(() -> {
            System.out.println("我先执行一次,而后等下一个线程执行完在执行");
            try {
                thread2.join();
                System.out.println("thread2------执行完了,到我执行了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();

在当前线程1中加入你要执行的线程2,等线程2执行完了在继续执行线程1,这样达到了按照顺序执行线程的目的,固然,你还能够在线程2中去join线程3,以此类推,其实就是将并行的线程串联起来了。

线程状态

常见的6种线程状态

当咱们在new一个线程的时候,可是尚未调用start()方法的时候,该线程处于新建状态

线程对象调用start方法的时候,它会被线程调度器进行执行,这个时候线程就已经交给操做系统来执行了,在操做系统执行的过程当中,这整个状态叫作Runnable,Runnable内部又有两个状态,一个是Ready就绪状态,一个是Running运行状态,就绪状态故名思意,我已经准备好了,可是还没运行,这个时候是cpu去处理何时去运行的。当真正交给cpu去运行的时候,当前线程就处理Running状态了。(当调用yield方法时,当前线程就会由Running状态,变为Ready状态,当被cpu再次执行的时候又会进入Running状态)

若是线程顺利执行完了就会进入Teminated结束状态,结束之后当前线程的使命就结束了,状态没法回退。

在Runnable状态还存在其余几种状态,TimeWaiting等待,Waiting等待Blocked阻塞。 在同步代码块中,没有获得锁就会进入Blocke阻塞状态,当得到锁之后就进入Ready就绪状态。 在线程运行过程当中若是调用了wait(),join(),LockSupport.park()就会进入到Waiting状态,调用notifiall(),LockSupport.unpark()就会回到Running状态。 TimeWaiting,看名字就知道是按照时间等待,等时间到了本身会回去,Thread.sleep(time),wait(time),jion(time),LockSupport.parkNanos(),LockSupport.parkUntil()这些都是关于时间等待的方法。

上面的全部状态均是由jvm进行管理的,jvm在使用线程的时候也要通过操做系统,jvm就是一个在操做系统上运行的程序。 线程挂起就是在当前线程执行过程当中cpu去执行另一个线程了,这属于cpu的调度,当在执行另一个线程的时候,当前线程就是被挂起了。

这里是我画的一个简陋的流程图

线程状态

相关文章
相关标签/搜索