Java--线程入门

进程与线程

单进程:在同一个时间段内只允许一个程序执行。
多进程:在一个时间段内可以同时运行多个程序(对资源进行轮流抢占,程序依次执行),但在同一个时间点,只允许一个程序执行,然后多核的出现就使得可以在同一个时间段上允许执行多个程序。
线程:在进程的基础上划分的更小的程序单元,线程依赖于进程的支持,线程的启动速度比进程的快速多

多线程的实现

如果要想在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 ThreadDemo {
    
    
	public static void main(String[] args) {
    
    
		new MyThread("线程A").start() ;//run()方法不能直接调用,要用start()去启动
		new MyThread("线程B").start() ;
		new MyThread("线程C").start() ;
	}
}

任何情况下,只要定义了多线程,多线程的启动永远只有一种方法:Thread类中的start()方法

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 ThreadDemo {
    
    
	public static void main(String[] args) {
    
    
		//Thread提供有一个构造方法:public Thread(Runnable target);
		Thread threadA = new Thread(new MyThread("线程A"));//调用Thread中的构造方法,将Runnable的子类对象传递过来,再调用Thread的start方法去启动
		Thread threadB = new Thread(new MyThread("线程B"));
		Thread threadC = new Thread(new MyThread("线程C"));
		threadA.start();//启动多线程
		threadB.start();//启动多线程
		threadC.start();//启动多线程
	}
}//run()方法不能直接调用,要用start()去启动

Runnable使用了函数式接口定义,所以也可以利用Lambda表达式实现

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 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.print1n(title + "运行,y ="+ y);
				}
			};
			new Thread(run).start() ;
		}
	}
}

Callable接口实现多线程

Runnable接口实现多线程有一个缺点:当线程执行完毕后,无法获取一个返回值。所以引出一个Callable接口

@FunctionalInterface.
public interface Callable< V> {
public V call() throws Exception ;
}

提供有一个call()方法,就有返回值
在这里插入图片描述

代码实现:

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<10;x++) {
    
    
			System. out. println("*********线程执行、x="+ x);
		}
		return "线程执行完毕。 ";
	}
}
public class ThreadDemo {
    
    
	public static void main(String[] args) throws Exception {
    
    
	FutureTask<String> task = new FutureTask<>(new MyThread()) ;
	new Thread(task). start();
	System.out.print1n("【线程返回数据】" + task.get());
	}
}

Thread和Runnable关系

Thread类的定义:

public class Thread extends Object implements Runnable { }

由thread的定义可知,Thread是Runnable的子类,所以在使用主体类继承Thread的时候覆写的run()方法还是Runnable的方法。
以第二个程序为例分析:
分析
在进行Thread 启动多线程的时候调用的是start()方法, 而后找到的是run()方法,但通过Thread类的构造方法传递了一个Runnable接口对象的时候,那么该接口对象将被Thread类中的target 属性所保存,在start()方法执行的时候会调用Thread类中的run()方法,而这个run()方法去调用Runnable接口子类被覆写过的run(方法
Thread主要描述的是线程,而资源的描述是通过Runnable完成的
在这里插入图片描述
以一个卖票的程序为例:

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.print1n("卖票,票号 ="+ this.ticket--);
		}
	}
}
public class ThreadDemo {
    
    
	public static void main(String[] args) {
    
    
		MyThread mt = new MyThread() ;
		new Thread(mt).start();//第一个窗口卖票
		new Thread(mt).start();//第二个窗口卖票
		new Thread(mt).start();//第三个窗口卖票
	}
}

在这里插入图片描述

多线程运行状态

在这里插入图片描述

  1. 任何一个线程的对象都应该使用Thread类进行封装,所以线程的启动使用的是start(),但是启动的时候实际上若干线程都将进入到一种就绪状态,现在并没有马上执行
  2. 进入到就绪状态之后就需要等待进行资源调度,当某一个线程调度成功之后则进入到运行状态(run()方法),但是所有的线程不可能一直持续执行下去,中间需要产生一些暂停的状态,例如:某个线程执行一段时间之后就需要让出资源进入到阻塞状态,随后重新回归到就绪状态;
  3. 当 run()方法执行完毕之后,实际上该线程的主要任务也就结束了,那么此时就可以直接进入到停止状态

猜你喜欢

转载自blog.csdn.net/qq_43337254/article/details/108037912