怎么样才算得上熟悉多线程编程?
第一,明白进程和线程的基本概念
第二,明白保护线程安全的基本方法有哪些
第三,明白这些线程安全的方法,包括互斥锁,自旋锁,无锁编程的适用的业务场景是什么?从OS和硬件角度说说原理是怎么样的?开销在哪里?
第四,能在现场借助cas操作,风险指针实现无锁的数据结构,比如无锁栈,无锁环形队列。无锁排序链表
下面就来学习一下多线程的知识然后进行实践
进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)
线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。
多进程是指操作系统能同时运行多个任务(程序)。
多线程是指在同一程序中有多个顺序流在执行。
在 java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口.(其实准确来讲,应该有三种,还有一种是实现Callable接口,并与Future、线程池结合使用,此文这里不讲这个,有兴趣看这里Java并发编程与技术内幕:Callable、Future、FutureTask、CompletionService )一、继承java.lang.Thread类
继承Thread类的方法是比较常用的一种,如果说你只是想起一条线程。没有什么其它特殊的要求,那么可以使用Thread.(推荐使用Runable,后头会说明为什么)。下面来看一个简单的实例
/**
* @author leon
* @createDate 2018年7月4日 下午5:13:25
* @version v1.0
* @classRemarks 多线程学习
*/
public class ThreadTest extends Thread{
private String name;
public ThreadTest(String name) {
super();
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name + "运行 : " + i);
try {
sleep((int) Math.random() * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadTest mTh1=new ThreadTest("A");
ThreadTest mTh2=new ThreadTest("B");
mTh1.start();
mTh2.start();
}
}
运行后输出结果:
但是start方法重复调用的话,会出现java.lang.IllegalThreadStateException异常。
二、实现java.lang.Runnable 接口
采用Runnable也是非常常见的一种,我们只需要重写run方法即可。下面也来看个实例。
运行结果如下
三、Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。总结:
实现Runnable接口比继承Thread类所具有的优势:
1)适合多个相同的程序代码的线程去处理同一个资源
2)可以避免java中的单继承的限制
3)增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4)线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
提醒一下大家:main方法其实也是一个线程。在java中所有的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM其实就是在操作系统中启动了一个进程。
四、线程状态转换
五、线程调度
六、线程常用函数说明
①sleep(long millis): 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)②join():指等待t线程终止。
使用方式。
join是Thread类的一个方法,启动线程后直接调用,即join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
比如 Thread t = new AThread(); t.start(); t.join();为什么要用join()方法
在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。