Java基础之多线程

92 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

1.进程与线程

进程:进程是程序的一次动态执行过程,对应了从代码加载,执行到完成的一个完整过程,这个过程也是从进程本身产生的

线程:线程是比进程更小的执行单位,进程可以产生多个线程,线程与进程类似;,但线程的中断和恢复更加节省系统的开销.

2.线程的状态与生命周期

线程一般有四个状态:

  1. 新建:当线程类或子类对象被创建时,就处于新建状态,并有了相应的内存空间和其它资源
  2. 运行:当jvm通过start()方法把cpu使用权交给该线程时,此线程脱离主线程开始生命周期.如果线程是thread的子类创建的,则执行该类中重写父类的run方法,而在线程没有结束时,不可以再让该线程调用start方法,否则发生IllegalThreadStateException异常.
  3. 中断:原因有四:JVM将cpu资源让给其它线程;执行了线程的sleep方法去进行休眠;执行了wait()方法去进入等待状态,等待时需要由其它线程调用notify()方法去通知它重新进入线程队列排队;进入阻塞状态.
  4. 死亡:处于死亡状态的线程不具有继续运行的能力,原因有二:已经完成全部工作;强制run()方法结束.死亡状态就是线程释放了实体,即释放分配给线程对象的内存.

3.线程的常用方法

1.start()方法:使之从新建状态进入到就绪状态排队,如已调用start方法,无需再调用,否则会出现异常

2.run()方法:定义线程对象被调度之后所执行的操作,在线程没有结束之前,不赞成让线程再调用start方法,否则出现异常

3.sleep(int 秒数):线程调用sleep方法去放弃CPU资源,休眠一段时间,如果休眠被打断,会抛出异常,异常必须在try-catch语句中调用sleep方法

4.isAlive():查看线程是否处在运行状态,返回true和false

ps:一个线程没有进入死亡状态时,无需分配实体,如果再分配,系统只能引用最后的实体,先前的实体就会存在,不会被垃圾收集器收集.

5.currentThread():是Thread类中的类方法,用类名调用,返回当前使用线程

6.interrupt():线程使用sleep可以用interrupt方法结束休眠重新排队

4.线程同步(synchronize)

目的:若许多线程都需要调用同一个方法时,必须等一个线程结束,另一个线程才能使用方法,不然则会产生混乱(如修改工资表时,先修改了才能发,不然给多钱咋办)

机制:当一个线程A使用synchronize方法时,其它线程想使用就必须等待,直到线程A使用完

5.协调同步的线程

目的:若一个线程使用中用到其它变量,但需要变量经过其它线程修改之后才可以使用,那么可以在同步线程中使用wait()方法去中断该线程的执行,直到其它线程把变量修改合适才使用notifyAll()方法去继续执行

6.守护线程

目的:线程默认是非守护线程,也称作用户(user)线程,线程可以调用setDaemon(boolean on)方法设置成守护线程,当用户线程已结束,守护线程里的run方法还没完成也会结束,所以可以使用守护线程做不重要的工作

下面是多线程使用代码,看懂代码就容易理解了

主线程main方法:


public class thead {

	@SuppressWarnings("null")
	public static void main(String[] args) throws InterruptedException {// 主线程执行main方法
		// TODO Auto-generated method stub
		// 线程第一种创建方法:用线程子类
		SpeakA b = new SpeakA();
		SpeakB w = new SpeakB();
		b.setPriority(10);// 设置线程优先权重 ,从1-10之间,不设置就为5,
		// JVM线程调度器的任务是使高优先级的线程可以始终运行,一旦时间片有空闲,则让同优先级的的线程轮流使用时间片
		b.start();//使用了线程联合方法
		w.start();

		// 线程第二种创建方法:实现Runnable接口方法(目标对象与线程完全解耦)
		Thread SpeakCC, SpeakDD; // 用Thread声明线程
		SpeakC sc = new SpeakC(); // 创建目标对象
		SpeakC sd = new SpeakC();
		SpeakCC = new Thread(sc); // 创建线程,目标对象是SpeakC,SpeakC必须实现Runnable接口
		SpeakDD = new Thread(sd);
		SpeakCC.setName("sc");
		SpeakDD.setName("sd");
		SpeakCC.start();
		SpeakDD.start();

		// 线程第二种创建方法:实现Runnable接口方法(目标对象组合线程弱耦合)使用了线程同步方法
		SpeakD D = new SpeakD();
		D.DD.start();
		D.EE.start();

		// 线程第二种创建方法:实现Runnable接口方法(目标对象组合线程弱耦合)使用了协调同步线程方法
		SpeakE E = new SpeakE();
		E.DD.start();
		E.EE.start();
	}

}

A方法


public class  SpeakA extends Thread {  //Thread类的子类创建线程
	
	SpeakB wa = new SpeakB();
	@Override
	public void run(){  //重写父类的run方法去执行线程所要做的工作
		for(int i=1;i<=15;i++){
			System.out.println("主人AAA"+i);
			
			try {
				wa.join();//线程联合,一起使用
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			if(i==5){
				System.out.println(Thread.interrupted());//查看线程是否被启动为true
				System.out.println("主人在睡觉了");
				try {
					Thread.sleep(1); //Thread休眠多少时间后继续进入队列排队
					
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		}
	}

}

B方法


public class SpeakB extends Thread {  //Thread类的子类创建线程
	
	public void run(){
		
		for(int i=1;i<=10;i++){
			System.out.println("下人在扫地"+i);
		}
	}

}

C方法


public class  SpeakC implements Runnable  { //实现Runnable接口


	public  void run() {
		// TODO Auto-generated method stub
		String name = Thread.currentThread().getName();//获取线程名字
		System.out.println(name);
		if(name=="sc"){
		for(int i=1;i<=10;i++){
			System.out.println("主母在喝茶"+i);
		}
	}else if (name=="sd"){
		for(int i=1;i<=10;i++){
			System.out.println("下人在泡茶"+i);
		}
	}
	}
	
	
	
}

D方法


public class SpeakD implements Runnable {

	Thread DD,EE;
	
	SpeakD(){
		DD=new Thread(this);//不加this无法指定
		EE=new Thread(this);
	}
	@Override
	public void run() {
		
		Thread t = Thread.currentThread();
		
		if(t==DD){
			System.out.println("我是DD");
			t.setName("DD");
			DE();
		
		}else if(t==EE){
			System.out.println("我是EE");
			t.setName("EE");
			DE();
		
		}
		// TODO Auto-generated method stub
		
		
	}
	
	public synchronized void  DE(){//线程同步synchronized修饰方法
		Thread t = Thread.currentThread();
		for(int i=1;i<=10;i++){
			System.out.println("我在使用,别人不能用,我是"+t.getName());
		}
		
	}

}

E方法


public class SpeakE implements Runnable {

	Thread DD,EE;
	
	SpeakE(){
		DD=new Thread(this);//不加this无法指定
		EE=new Thread(this);
	}
	@Override
	public void run() {
		int i = 10;
		
		Thread t = Thread.currentThread();
		
		if(t==DD){
	
			t.setName("DD");
			try {
				DE(i);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		}else if(t==EE){
		
			t.setName("EE");
			
			try {
				i=i+20;
				DE(i);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		}
		// TODO Auto-generated method stub
		
		
	}
	
	public synchronized void  DE(int i) throws InterruptedException{//线程同步synchronized修饰方法
		Thread t = Thread.currentThread();
	while(i<20){
		System.out.println("我没资格用,我是"+t.getName());
		wait();//wait方法停止线程
		i=i+20;
		System.out.println("我充20块钱,我有资格了"+t.getName());
	}
			notifyAll();//叫醒停止的所有进程
			System.out.println("我有资格用,我是"+t.getName());
	
	}

}