Java-基础(三十六)线程相关

引言:

1:windows是一个绝对的多线程操作系统。

2:进程是在操作系统上的划分,线程是在操作系统上的划分。

3:Java是多线程的编程语言,所以Java在进行并发访问处理的时候可以得到更高的处理性能。

什么是线程和进程

背景:在Java语言里面最大的特点是支持多线程的开发(为数不多的支持多线程的编程语言)。

1:什么是进程

在这里插入图片描述
在这里插入图片描述

2:什么是进程

在这里插入图片描述
3:继承Thread类实现多线程

如果要想在Java中实现多线程的定义,就需要有一个专门的线程主体类进行线程的执行任务的定义,这个线程主体类实现特定或者继承特定的父类才可以完成。

第一种实现多线程方式(继承Thread类)

在这里插入图片描述

 class MyThread extends Thread {	// 线程的主体类
	private String title ;
	public MyThread(String title) {
		this.title = title ;
	}
	@Override
	public void run() {	// 线程的主体方法
		for (int x = 0 ; x < 10 ; x ++) {
			System.out.println(this.title + "运行,x = " + x);
		}
	}
} 
 public class Demo00001{
	 public static void main(String args[]) {
		new  MyThread("线程A").start();
		new  MyThread("线程B").start();
		new  MyThread("线程C").start(); 
	 }
 }
 //运行结果
 线程A运行,x = 0
线程C运行,x = 0
线程B运行,x = 0
线程A运行,x = 1
线程B运行,x = 1
线程C运行,x = 1
线程C运行,x = 2
线程C运行,x = 3
线程C运行,x = 4
线程C运行,x = 5
线程C运行,x = 6
线程C运行,x = 7
线程C运行,x = 8
线程C运行,x = 9
线程B运行,x = 2
线程B运行,x = 3
线程B运行,x = 4
线程B运行,x = 5
线程B运行,x = 6
线程B运行,x = 7
线程B运行,x = 8
线程B运行,x = 9
线程A运行,x = 2
线程A运行,x = 3
线程A运行,x = 4
线程A运行,x = 5
线程A运行,x = 6
线程A运行,x = 7
线程A运行,x = 8
线程A运行,x = 9

 //虽然调用的是start()方法,但是最终执行的是run()方法,并且所有的线程对象都是交替执行的。

所有的要执行的功能都在run()方法中定义。说明

在正常情况下如果要想使用类中的一个方法,那么肯定要产生实例化对象,而后去调用类中提供的方法,但是run()方法是不能够被直接调用的,因为这里牵扯到操作系统的资源调度问题,所以要想启动多线程必须使用start()方法完成。

4:实际的调用过程

在Java程序执行的过程中考虑到对于不同层次开发者的需求,所以其支持有本地的操作系统调用,而这项技术就被称为JNI(Java Native Interface)技术,但是Java开发过程中并不推荐这样使用,利用这项技术可以使用一些操作系统提供底层函数进行特殊的处理,而在Thread类里面提供的start0()就表示将此方法依赖于不同的操作系统实现。

在这里插入图片描述

5:为什么多线程的启动不直接使用run()方法而必须使用Thread类中的start()方法呢?

查看一下start()方法的实现操作,看它的源代码。

在这里插入图片描述

发现在start()方法里面会抛出一个“IllegalThreadStateException”异常类对象,但是整个的程序并没有使用throw或者明确的try catch处理,因为该异常一定是RuntimeException的子类。

6:每个线程对象只允许启动一次

如果一个线程对象重复启动就会抛出此异常,

class MyThread extends Thread {	// 线程的主体类
	private String title ;
	public MyThread(String title) {
		this.title = title ;
	}
	@Override
	public void run() {	// 线程的主体方法
		for (int x = 0 ; x < 10 ; x ++) {
			System.out.println(this.title + "运行,x = " + x);
		}
	}
} 
public class Test {
	public static void main(String[] args) {
		MyThread mt = new MyThread("线程A") ;
		mt.start() ;
		mt.start() ;  // 重复进行了线程的启动
	}
}

Exception in thread “main” java.lang.IllegalThreadStateException

7:基于Runnable接口实现多线程

虽然可以通过Thread类的继承来实现多线程的定义,但是在Java程序里面对于继承永远都是参在单继承局限的,所以在Java里面又提供有多线程的主体定义结构形式,实现java.lang.Runnable接口,此定义如下:

在这里插入图片描述

通过Runnable实现多线程的主体类

class MyThread implements Runnable {	// 线程的主体类
	private String title ;
	public MyThread(String title) {
		this.title = title ;
	}
	@Override
	public void run() {	// 线程的主体方法
		for (int x = 0 ; x < 10 ; x ++) {
			System.out.println(this.title + "运行,x = " + x);
		}
	}
}  


public class Test {
	public static void main(String[] args) {
		Thread threadA = new Thread(new MyThread("线程对象A")) ;
		Thread threadB = new Thread(new MyThread("线程对象B")) ;
		Thread threadC = new Thread(new MyThread("线程对象C")) ;
		threadA.start(); // 启动多线程
		threadB.start(); // 启动多线程
		threadC.start(); // 启动多线程
	}
}

在上面的代码中,此时的MyThread类中也不再支持有start()这个方法,可是如果不使用Thread.start()方法是无法进行多线程启动的,那么这个时候看下Thread类所提供的构造方法:

构造方法:public Thread (Runnable target);

8:利用Lambda实现多线程实现多线程定义

public class ThreadDemo {
	public static void main(String[] args) {
		for (int x = 0 ; x < 3 ; x ++) {
			String title = "线程对象-" + x ;
			Runnable run = ()->{
				for (int y = 0 ; y < 10 ; y ++) {
					System.out.println(title + "运行,y = " + y);
				}
			} ;
			new Thread(run).start(); 
		}
	}
}
public class Test {
	public static void main(String[] args) {
		for (int x = 0 ; x < 3 ; x ++) {
			String title = "线程对象-" + x ;
			new Thread(()-> { 
				for (int y = 0 ; y < 10 ; y ++) {
					System.out.println(title + "运行,y = " + y);
				}
			}).start(); 
		}
	}
}

在以后的开发之中,对于多线程的实现,优先考虑的就是Runnable接口实现,并且永恒都是通过Thread类对象启动多线程。

9:Thread于Runnable关系

经过一系列的分析之后可以发现,在多线程的实现过程中有了两种做法:Thread类,Runnable接口,如果从代码的结构本身来讲使用Runnable是最方便的,因为其可以避免单继承的局限,同时也更好的进行功能的扩充。

下面观察Thread和Runnable的联系:

在这里插入图片描述

发现现在在Thread类也是Runnable接口的子类,那么在继承Thread类的实际上还是覆写的Runnable接口中的run()方法。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

高并发访问:产生的线程数量太多了

实际上就是多个线程对象抢占资源的操作。

class MyThread implements Runnable {	// 线程的主体类
	private int ticket = 5 ;
	@Override
	public void run() {	// 线程的主体方法
		for (int x = 0 ; x < 100 ; x ++) {
			if (this.ticket > 0) { 
				System.out.println("卖票,ticket = " + this.ticket --);
			}
		}
	}
}  
public class Test {
	public static void main(String[] args) {
		MyThread mt = new MyThread() ;
		new Thread(mt).start(); 	// 第一个线程启动	
		new Thread(mt).start(); 	// 第二个线程启动	
		new Thread(mt).start(); 	// 第三个线程启动	
	}
}
//卖票,ticket = 5
卖票,ticket = 4
卖票,ticket = 2
卖票,ticket = 3
卖票,ticket = 1

上述代码中的内存操作 如下;

在这里插入图片描述

mt是Runnable 接口的对象,new Thread表示多个客户端线程抢占资源的操作。

10:Callable实现多线程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class MyThread implements Callable<String> {
	@Override
	public String call() throws Exception {
		for (int x = 0 ; x < 5 ; x ++) {
			System.out.println("********* 线程执行、x = " + x);
		}
		return "线程执行完毕。";
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		FutureTask<String> task = new FutureTask<>(new MyThread()) ;
		new Thread(task).start(); 
		System.out.println("【线程返回数据】" + task.get());
	}
}
//********* 线程执行、x = 0
//********* 线程执行、x = 1
//********* 线程执行、x = 2
//********* 线程执行、x = 3
//********* 线程执行、x = 4
//【线程返回数据】线程执行完毕。

在这里插入图片描述

11:线程运行时状态

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_35649064/article/details/83895556