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("主函数执行了"); } } }
咱们看一下执行结果,暂时不要理会如今的写法学习
主函数执行了 启动了一个线程 主函数执行了 启动了一个线程 主函数执行了 启动了一个线程 启动了一个线程 主函数执行了 主函数执行了 启动了一个线程 主函数执行了 启动了一个线程 主函数执行了 启动了一个线程 主函数执行了 启动了一个线程 启动了一个线程 主函数执行了 主函数执行了 启动了一个线程
咱们能够看见它是交替运行的
平时咱们的代码都是串行的,也就是顺序执行,而如今这钟状况就是并行的状态,这就是线程一个比较直观的概念操作系统
这里列举几种线程经常使用的几种方式
经过继承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,以此类推,其实就是将并行的线程串联起来了。
当咱们在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的调度,当在执行另一个线程的时候,当前线程就是被挂起了。
这里是我画的一个简陋的流程图