JAVA多线程技术学习笔记(一)——多线程基本概念

JAVA多线程技术学习笔记(一)——多线程基本概念 

什么是进程?

我在一家公司面试的时候面试官问了我这样一个问题:什么是进程?我知道怎么创建线程,知道怎么操作,唯独就忘记了这个怎么表述,尴尬。我告诉他进程是这个

                                                         JAVA多线程技术学习笔记(一)——多线程基本概念_第1张图片

然后他就问我对,那这个是什么呢???我是没答上来,回去百度了答案是这么说的:“进程是操作系统结构的基础,是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动;是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的独立单位。”

什么是线程?

线程是进程的一部分,一个进程可以分出好几个线程,比如:我使用网易云音乐,我可以下载歌曲,同时还能听歌,看评论等不同的功能同时在运行,这些不同的功能就可以理解为是一个“线程”。没有线程的进程可以被看做是单线程的,也是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();
	}
}

Java支持多实现,所以实现Runnable的方法比较灵活,所以通常推荐采用这种创建线程模式.获取当前线程需采用 Thread.currentThread()来获取

3.通过CallableFutureTask创建线程

public class ThreadDome implements Callable {

	@Override
	public String call() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("使用Callable创建线程开启");
		return null;
	}
	
	public static void main(String[] args){ 
		FutureTask 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("谢谢!线程停止");
	}
	
}
 输出结果如下: 
     
 
     
 
     
 
    
JAVA多线程技术学习笔记(一)——多线程基本概念_第2张图片
不仅如此,这两个方法还是非同步的(在之后的同步文章中会说明),所以被弃用了。
线程的优先级
currentThread():代指运行时的线程,可以通过这个方法来获取线程的一些信息。
sleep():使线程进入休眠状态(具体的在之后线程通信时讲)。
isAlive():判断线程是否处于休眠/活跃状态。
getId():获取线程的唯一标识。

你可能感兴趣的:(Java,SE)