JAVA多线程技术学习笔记(一)——多线程基本概念
程序员文章站
2022-05-04 18:18:55
...
JAVA多线程技术学习笔记(一)——多线程基本概念
什么是进程?
我在一家公司面试的时候面试官问了我这样一个问题:什么是进程?我知道怎么创建线程,知道怎么操作,唯独就忘记了这个怎么表述,尴尬。我告诉他进程是这个
然后他就问我对,那这个是什么呢???我是没答上来,回去百度了答案是这么说的:“进程是操作系统结构的基础,是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动;是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的独立单位。”
什么是线程?
线程是进程的一部分,一个进程可以分出好几个线程,比如:我使用网易云音乐,我可以下载歌曲,同时还能听歌,看评论等不同的功能同时在运行,这些不同的功能就可以理解为是一个“线程”。没有线程的进程可以被看做是单线程的,也是CPU调度的基本单位。
线程与进程的区别
线程的改变只是代表了CPU执行过程的改变,而没有发生进程拥有的资源变化,进程拥有一个完整的地址空间,不依赖线程的独立存在,而进程则相反,没有自己的独立空间,域进程内部的其他线程一起共享分配的所以资源。
如何使用JAVA创建一个线程?
既然现在已经大致知道了什么是Java多线程,那么如何创建一个java线程呢?创建Java线程的方式有一下两种
1.继承Thread类
public class ThreadDome extends Thread {
public void run() {
System.out.println("继承Thread线程开启");
}
public static void main(String[] args){
ThreadDome t1= new ThreadDome();
t1.start();
}
}
Thread类是一个Rannable接口的实现,采用这种方法创建一个线程最大的就行就是Java只支持单继承,继承了该类就不能进行其他的扩展。优点就是可以较为简单快捷的创建一个线程,获取这个线程可以直接使用this即可
2.实现Runnable接口
public class ThreadDome implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("实现Runnable线程开启");
}
public static void main(String[] args){
Thread t1= new Thread(new ThreadDome());
t1.start();
}
}
3.通过Callable和FutureTask创建线程
public class ThreadDome implements Callable<String> {
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
System.out.println("使用Callable创建线程开启");
return null;
}
public static void main(String[] args){
FutureTask<String> newFT=new FutureTask<>(new ThreadDome());
Thread t1=new Thread(newFT);
t1.start();
}
}
这第三种方式个人感觉与第二种类似,感觉就像是创建了一个线程任务,当需要开启线程时就通过创建一个Thread对象将任务传入线程开启线程的执行。
Thread类中的常用的函数
线程的开启
run()和star()
这两种方法都是可以执行线程run内的代码的,但是不同的是run方法是在本线程内执行,也就是单线程执行,可视为调用一个普通方法。而star是一个多线程的调用方式,所以开启多线程时需要使用的时star()方法。
线程的关闭
1.异常停止法(推荐使用)
interrupt:该方法是对线程打了一个停止标志,但是不能真正停止。
interrupted:测试线程是否中断,执行后将将状态标志清除为false。(还有 isInterrupt:测试线程是否是中断的。)
结合这两个函数停止线程的方式
public class Test1 extends Thread {
public static void main(String[] args) throws InterruptedException{
Thread a=new Test1();
a.start();
Thread.sleep(200);
//打上中断标记
a.interrupt();
}
@Override
public void run() {
super.run();
int i=0;
try{
while(true){
System.out.println(i++);
if(Thread.interrupted()){
//抛出中断错误
throw new InterruptedException();
}
}
}catch(InterruptedException e){
System.out.println("thread is stop");
e.printStackTrace();
}
}
}
2.直接停止法
stop():直接停止线程(已被弃用),暴力停止会导致一些清理性工作不能完成,还肯破坏数据同步处理
public class Test1 extends Thread {
public static void main(String[] args) throws InterruptedException{
Thread a=new Test1();
a.start();
}
@Override
public void run() {
super.run();
int i=0;
while(true){
System.out.println(i++);
if(i>100){
this.stop();
}
}
}
}
3.运行结束自动停止
线程暂停和启动
suspend()和resume():线程的暂停和重启,现在已经被弃用了。首先这两个方法有明显的缺点:对资源的独占,极易发送死锁。如下面代码例如下面这一段代码:
public class SuspendTest {
public static void main(String[] args){
Thread t1=new Thread(){
public void run(){
synchronizedprintln.synprint("a");
}
};
t1.start();
Thread t2=new Thread(){
public void run(){
System.out.println("抱歉资源被占用!");
synchronizedprintln.synprint("b");
}
};
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
}
}
class synchronizedprintln {
synchronized public static void synprint(String a) {
System.out.println("你好!线程开始");
if("a".equals(a)){
System.out.println("抱歉!线程停止");
Thread.currentThread().suspend();
}
System.out.println("谢谢!线程停止");
}
}
输出结果如下:
不仅如此,这两个方法还是非同步的(在之后的同步文章中会说明),所以被弃用了。
线程的优先级
currentThread():代指运行时的线程,可以通过这个方法来获取线程的一些信息。
sleep():使线程进入休眠状态(具体的在之后线程通信时讲)。
isAlive():判断线程是否处于休眠/活跃状态。
getId():获取线程的唯一标识。
上一篇: Java基础之多线程-多生产多消费