胡八一之Java(八):多线程

多线程的优势:多进程运行需要独立的内存空间,而多线程可以共享内存,从而提高了线程的运行效率。

创建线程一般使用两种方式:

1、继承Thread类:

import java.io.IOException;


public class Test extends Thread {
	private int i=0;
	public void run() {
		for(;i<100;i++) {
			System.out.println(this.getName()+":"+i);
		}
	}
 public static void main(String[] args) throws IOException {
    for(int i =0;i<100;i++) {
    	System.out.println(Thread.currentThread().getName()+" :"+i);
    	if(i == 20) {
    		//创建并启动线程一
    		new Test().start();
    		//创建并启动线程二
    		new Test().start();
    	}
    }
 }
}

2、通过实现Runnable接口:

import java.io.IOException;


public class Test implements Runnable {
	private int i=0;
	public void run() {
		for(;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}
 public static void main(String[] args) throws IOException {
    for(int i =0;i<100;i++) {
    	System.out.println(Thread.currentThread().getName()+" :"+i);
    	if(i == 20) {
    		Test t =new Test();
    	   //通过new Thread(target,name)的方式来启动线程
    		new Thread(t,"线程一").start();
    		new Thread(t,"线程二").start();
    	}
    }
 }
}

这两种方式的区别:

通过继承Thread类创建多线程,获得线程对象比较简单,通过this即可获得,而通过实现Runnable接口创建多线程,需要通过Thread.currentThread()方法来获得当前线程对象。前者创建Thread子类便可代表线程对象,后者创建的Runnable只能作为线程对象的target。

两种方式的对比:

通过继承Thread类创建线程较为简单,但Java是单继承,所以无法继承其他类。

通过实现Runnable接口,如果需要访问当前线程对象,需要通过Thread.currentThread()方法来访问,但它优点就是可以继承其他类,多线程共享一个target对象,非常适合多线程共享一份资源的情况。

因此,一般采用实现Runnable接口的方法实现多线程。

 

线程的生命周期:新建(new),就绪(Runnable),运行(Running),阻塞(Blocked),和死亡(Dead)

 

join线程:

当在某个程序中执行流调用其他线程的join()时,则当前线程被阻塞,知道被join()加入的join线程执行完毕以后。

import java.io.IOException;


public class Test implements Runnable {
	private int i=0;
	public void run() {
		for(;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}
 public static void main(String[] args) throws IOException, InterruptedException {
    for(int i =0;i<100;i++) {
    	System.out.println(Thread.currentThread().getName()+" :"+i);
    	if(i == 20) {
    		Test t =new Test();
    	   //通过new Thread(target,name)的方式来启动线程
    		Thread j1 =new Thread(t,"被jion的线程");
    		j1.start();
    		j1.join();
    		
    	}
    }
 }
}

运行部分结果:

main :18
main :19
main :20
被jion的线程:0
被jion的线程:1
被jion的线程:2
被jion的线程:3

可以看到,当主线程运行到20时被阻塞,在被join线程执行完后才会执行main线程。

后台线程:

有一种线程,叫做“守护线程”,为其他线程提供服务,被称为后台线程。JVM的垃圾回收机制就是典型的后台线程。

特征:当前台线程死亡后,后台线程将随之死亡。

调用Thread对象的setDaemon(true)方法可将指定线程设置为后台线程。Thread类还提供了一个isDaemon()方法来判断是否为后台线程。

下面程序展示了当前台线程执行完毕死亡后,后台线程也随之死亡。

import java.io.IOException;


public class Test implements Runnable {
	private int i=0;
	public void run() {
		for(;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}
 public static void main(String[] args) throws IOException, InterruptedException {
   
 
    	Test t =new Test();
    	Thread b =new Thread(t,"后台线程");
    	//将其设置为后台线程
    	b.setDaemon(true);
    	//启动后台线程
    	b.start();
    	for(int i =0;i<10;i++) {
    	
    	   	System.out.println(Thread.currentThread().getName()+" :"+i);
    	}
    }
 }

运行结果:

main :0
main :1
main :2
main :3
main :4
后台线程:0
main :5
后台线程:1
后台线程:2
main :6
main :7
main :8
main :9
后台线程:3
后台线程:4
后台线程:5
后台线程:6
后台线程:7
后台线程:8
后台线程:9
后台线程:10

 

线程睡眠:sleep

如果需要让当前线程暂停一段时间,让出cpu资源,并进入阻塞状态,则可以通过调用Thread类的静态sleep()方法实现。

程序如下:

import java.io.IOException;


public class Test implements Runnable {
	private int i=0;
	public void run() {
		for(;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}
 public static void main(String[] args) throws IOException, InterruptedException {
   
 
    	Test t =new Test();
    	Thread b =new Thread(t,"线程一");
        //启动线程
    	b.start();
    	for(int i =0;i<10;i++) {
    	    
    	   	System.out.println(Thread.currentThread().getName()+" :"+i);
    	   	if(i ==5) {
    	   		Thread.sleep(1000);
    	   	}
    	}
    }
 }

线程让步:yield

上述的sleep()方法会将当前线程进入阻塞状态,但yield()方法不会阻塞该线程,会将其转入就绪状态。yield()只是当前线程暂停一下,让系统的线程调度器重新调度一次,完全可能的情况是:线程调度器又将其调度出来执行。

import java.io.IOException;


public class Test implements Runnable {
	private int i=0;

	public void run() {
		for(;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
			if(i==20) {
				Thread.yield();
			}
		}
	}
 public static void main(String[] args) throws IOException, InterruptedException {
   
 
    	Test t =new Test();
    	Thread b =new Thread(t,"高级线程");
    	//将线程设置为最高优先级
    	//b.setPriority(Thread.MAX_PRIORITY);
        //启动线程
    	b.start();
    	Thread c = new Thread(t,"低级线程");
    	//将线程设置为最低优先级
    	//c.setPriority(Thread.MIN_PRIORITY);
    	//启动线程
    	c.start();
    
    }
 }

yield()静态方法在没有设置优先级的情况下会让其调度器重新调度,在设置了优先级的情况下,只能调度其同等优先级或者更高优先级的线程。

关于sleep()方法和yield()方法的区别:

sleep()方法暂停当前线程后,会不理会其他线程的优先级,让其他线程获得运行机会。但yield()只会调度其同等优先级或者更高优先级的线程。

sleep()方法让线程转入阻塞状态,直到经历完阻塞时间后才会进入就绪状态,而yield()强制让当前线程进入就绪状态,所以完全有可能调用的还是当前线程。

sleep()方法声明了InteruptedExecption异常,所以调用该方法时要么捕捉该异常,要么显式抛出该异常;而yield()方法则没有声明抛出任何异常。

sleep()方法比yield()有更好的移植性,所以不建议使用yield()方法来控制并发线程的执行。

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值