Java教程

18.多线程基础

本文主要是介绍18.多线程基础,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

@一贤爱吃土豆

1.进程

  • 是系统进行资源分配调用的基本单位,每个进程都有自己独立的内存空间和系统资源.
  • (正在运行的程序)
    cpu时间片:指系统资源和内存空间.
    在这里插入图片描述

2.线程

  • 是进程中一条执行线路.每个线程都要执行一个任务.
  • 线程是CPU的基本调度单位.

3.进程与线程的关系

  • 一个进程可以有1个到多个线程.
  • 一个线程永远只属于一个进程.
  • 一个进程中多个线程之间是互抢资源的竟争关系.

4.实现线程

  • 有三种实现线程的方式,前两种常用,第三周基本不用.

4.1:继承Thread方式实现线程

eg:/**
 * 线程子类
 * @author sx
 * @version 1.0 2020年10月28日
 */
public class MyThread extends Thread{
	/**
	 * 重写父类中任务方法
	 */
	@Override
	public void run() {
		for (int i = 1; i <= 10; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}
}

public static void main(String[] args) {
		//创建子线程对象
		MyThread t1=new MyThread();
		MyThread t2=new MyThread();
		
		//启动线程
		t1.start();
		t2.start();
	}

4.2:实现Runnable接口的方式实现线程

eg:/**
 * 任务类
 * @author sx
 * @version 1.0 2020年10月28日
 */
public class MyRunnable implements Runnable{
	/**
	 * 重写父接口中任务方法
	 */
	@Override
	public void run() {
		for (int i = 1; i <=10; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}
		  }

		public static void main(String[] args) {
		//创建任务对象
		MyRunnable m1=new MyRunnable();
		MyRunnable m2=new MyRunnable();
		
		//创建线程对象
		Thread t1=new Thread(m1);
		Thread t2=new Thread(m2);
		
		//启动线程
		t1.start();
		t2.start();
	}

4.3:实现Callable接口的方式实现线程

  • (了解,现在基本不用).

5.继承Thread VS 实现Runnable接口的方式实现多线程

5.1:代码简洁性

  • 继承Thread方式实现线程代码更简洁;
  • 实现Runnable接口的方式实现多线程较复杂.

5.2:扩展性

  • 继承Thread方式实现线程,这个类无法再继承其他类,只能实现其他接口,扩展性较差;
  • 实现Runnable接口的方式实现线程,这个类还可以再继承其他的类,实现其他的接口,所以扩展性较好.

5.3:资源共享性

  • 继承Thread方式实现多个线程,如果这多个线程想要执行同一个任务,那这个任务得定为静态才能实现共享,可是静态耗资源,所以共享性不好.
  • 实现Runnable接口的方式实现多个线程,如果这多个线程想要执行同一个任务,只需要给这多个线程传递同一个任务对象,所以共享性好.

6.给线程取名:

6.1:每个线程都有默认名字.

6.2:用构造方法给线程取名.

eg:/**
 * 线程子类
 * @author sx
 * @version 1.0 2020年10月28日
 */
public class MyThread extends Thread{
	/**
	 * 有参构造,给线程取名
	 * @param string
	 */
	public MyThread(String name) {
		super(name);
	}

	/**
	 * 重写父类中任务方法
	 */
	@Override
	public void run() {
		for (int i = 1; i <= 10; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}
}

6.3:在线程子类声明一个属性专门用来存线程名称.

6.4:调用线程对象setName(“名称”)

7.线程休眠

  • 让当前的线程让出资源,停止对资源的抢夺,暂停指定时间,等时间到了,重新参与资源的抢夺.
  • 语法:Thread.sleep(毫秒数); 或 线程对象名.sleep(毫秒数);
eg:public static void main(String[] args) throws InterruptedException {
		for (int i = 6; i >=1; i--) {
			System.out.println(i);
			Thread.sleep(1000);
		}
	}

8.线程优先级

  • 线程优先级越高抢占资源的概率越高到,不一定能抢;线程优先级越低抢占资源的概 率越低,但不一定抢不到.
  • 注意:线程优先级一定要在线程启动之前设置才有效.
  • 语法:线程对象名.setPriority(int newPriority);
eg:public static void main(String[] args) {
		//创建线程对象
		MyThread t1=new MyThread();
		MyThread t2=new MyThread();
		//给线程取名
		t1.setName("线程A");
		t2.setName("线程B");
		
		//设置线程优先级
		t1.setPriority(Thread.MIN_PRIORITY);
		t2.setPriority(Thread.MAX_PRIORITY);
		
		//启动线程
		t1.start();
		t2.start();
	}

9.线程合并

  • 将多个线程合并为一个线程,合并过来的线程先执行完,再执行原线程剩下部分.
  • 语法:线程对象名.join();

9.1:让子线程合并主线程中:合并过来的子线程先运行完,再运行主线程剩下部分.

eg:public static void main(String[] args) throws InterruptedException {
		//创建子线程对象
		Thread t1=new Thread(new Runnable() {
			/**
			 * 重写父接口中任务方法
			 */
			@Override
			public void run() {
				for (int i = 1; i <=100; i++) {
					System.out.println(Thread.currentThread().getName()+":"+i);
				}
			}
		}, "线程A");
		
		//启动子线程对象
		t1.start();
		
		for (int i = 1; i <=100; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
			//当主线程运行10时,让子线程A合并过来
			if (i==10) {
				t1.join();
			}
		}
	}

9.2:让子线程A合并子线程B中:合并过来的子线程A先运行完,再运行子线程B剩下部分.

eg:public class MyThread extends Thread{
	//声明一个属性存线程对象
	public MyThread t;
	
	/**
	 * 任务方法
	 */
	@Override
	public void run() {
		for (int i = 1; i <=100; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
			//当子线程B运行10时,让子线程A合并过来
			if (i==10&&Thread.currentThread().getName().equals("线程B")) {
				try {
					//this指代线程B对象
					this.t.join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

public static void main(String[] args) throws InterruptedException {
		//创建线程对象
		MyThread tA=new MyThread();
		MyThread tB=new MyThread();
		//给线程取名
		tA.setName("线程A");
		tB.setName("线程B");
		
		//给对象的属性赋值,让线程A作为线程B对象的一个属性
		tB.t=tA;
		tA.t=null;
		
		//启动线程
		tA.start();
		tB.start();
	}

10.线程礼让:让当前的线程让出资源,重新抢夺.

  • 语法:Thread.yield(); 或者 线程对象.yield();
eg:public static void main(String[] args) {
		//创建线程对象
		Thread ta=new Thread(new Runnable() {
			/**
			 * 重写父接口中任务方法
			 */
			@Override
			public void run() {
				for (int i = 1; i <=100; i++) {
					System.out.println(Thread.currentThread().getName()+":"+i);
				}
			}
		}, "线程A");
		
		//启动线程
		ta.start();
		
		for (int i = 1; i <=100; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
			//主线程每运行一次就礼让一次
			Thread.yield();
		}
	}

11.线程中断

11.1:用中断方法

  • interrupt()改变线程的中断状态,
  • isInterrupted()判断线程的状态是否中断.
eg:public static void main(String[] args) throws InterruptedException {
		//创建线程对象
		Thread ta=new Thread(new Runnable() {
			/**
			 * 重写父接口中任务方法
			 */
			@Override
			public void run() {
				for (int i = 1; i <=100; i++) {
					//判断当前的线程中断状态是否为true
					if (Thread.currentThread().isInterrupted()==true) {
						break;
					}
					System.out.println(Thread.currentThread().getName()+":"+i);
				}
			}
		}, "线程A");
		
		//启动线程
		ta.start();
		
		for (int i = 1; i <=100; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
			//当主线程运行10时,中断子线程A的执行
			if (i==10) {
				//改变子线程当前中断状态
				ta.interrupt();
				//主线程休眠将资源让出来,这样子线程的中断才会生效
				Thread.sleep(2000);
			}
		}
	}

11.2:用一个变量作标记,标记线程是否需要中断

eg:public class InterruptTest2 {
	//声明一个变量作标记,标记子线程是否中断,默认不中断
	static	boolean flag=false;

	public static void main(String[] args) throws InterruptedException {
		//创建线程对象
		Thread ta=new Thread(new Runnable() {
			/**
			 * 重写父接口中任务方法
			 */
			@Override
			public void run() {
				for (int i = 1; i <=100; i++) {
					//判断当前的线程中断标记是否为true
					if (flag) {
						break;
					}
					System.out.println(Thread.currentThread().getName()+":"+i);
				}
			}
		}, "线程A");
		
		//启动线程
		ta.start();
		
		for (int i = 1; i <=100; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
			//当主线程运行10时,中断子线程A的执行
			if (i==10) {
				//改变中断标记
				flag=true;
				//让主线休眠,这样子线程就能抢到资源运行生效
				Thread.sleep(1000);
			}
		}
	}
}

12.守护线程(后台线程,精灵线程)

  • 守护线程守护所有非守护线程,当一个进程中所有的非守护线程死亡了,守护线程自动死亡.
  • 注意:设置线程为守护线程时,一定要在启动线程之前设置才有效.
  • 语法:线程对象.setDaemon(true);
eg:public static void main(String[] args) {
		//创建线程对象
		Thread t1=new Thread(new Runnable() {
			/**
			 * 重写父接口中任务方法
			 */
			@Override
			public void run() {
				for (int i = 1; i <=1000; i++) {
					System.out.println(Thread.currentThread().getName()+":"+i);
				}
			}
		}, "守护线程");
		
		//设置子线程为守护线程
		t1.setDaemon(true);
		
		//启动线程
		t1.start();
		
		for (int i = 1; i <=10; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}

13.线程生命周期:(面试经典)

在这里插入图片描述

13.1:初始状态(新建状态)

  • 当一个线程对象刚被new(创建)出来时,这个线程对象就处于初始状态.

13.2:就绪状态

  • 当一个线程对象调用start(),或阻塞(sleep(),wait())的线程本来后就处于就绪状态.

13.3:运行状态

  • 当就绪状态的线程抢到cpu时间片,调用run()时,这时线程就处于运行状态.

13.4: 阻塞状态

*当一个线程调用sleep()或wait()时,这个线程就处于阻塞状态.

13.5:终止状态(死亡状态)

  • 当一个线程不能再执行时(任务执行完或被中断),这个线程就等于终止状态.

总结:
1.了解HashTable和Properties
2.集合的总结(重点)
3.异常定义及分类
4.异常的处理机制(try-catch-finally和throws)(重点)
5.自定义异常
6.进程和线程的定义及区别(重点)
7.实现线程的两种方式(重点)
8.给线程取名
9.继承Thread VS 实现Runnable接口的方式实现多线程(重点)
10.实现线程的第三种方式(了解)
11.线程休眠(重点)
12.线程优先级(了解)
13.线程合并(重点)
14.线程礼让(了解)
15.线程中断(重点)
16.守护线程
17.线程生命周期(重点)
18.线程池(重点)

这篇关于18.多线程基础的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!