黑马程序员——【学习笔记】多线程——多线程概述及其建立

-------android培训java培训、期待与您交流!----------



多线程是指在一个线程里通过多个执行单元各自执行对应的内容的技术。


1.1 进程:

进程就是一个正在执行的程序实例。即可以分配给处理器并由处理器执行的一个实体。需要强调进程是一个“执行中的”程序,只有处理器赋予这个程序以活动能力,它才能称为一个活的程序实体,即进程。

每一个进程都被系统赋予它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存放处理器执行的代码,数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。 

1.2 线程:

线程是进程运行中的一个执行路径。


1.3 进程和线程的区别: 

进程和线程的主要差别在于它们是不同的操作系统资源管理方式。

进程有独立的地址空间,一个进程崩溃后,不会对其他进程造成影响;

而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉。

所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。 

总的来说,线程依附进程的地址空间而存在,线程是进程执行路径。而同时进程必须保证线程的顺利执行从而保证进程自身的健壮(即不面临崩溃)。一个进程中可以有多个执行路径,就是多线程。


1.4 多线程的利弊:

多线程的好处:解决了多部分代码同时运行的问题。

多线程的弊端:因为虽然说是多线程,但是多个线程同时执行的实质的CPU做着快速切换完成。单个CPU每次只能执行一个线程这个是不会变的。而且这个切换是随机的,具有不稳定性。所以线程太多的话,会导致运行效率降低。


PS:JVM启动时启动了多条线程,至少有两条是明确的:执行主程序main函数的线程;负责回收垃圾的线程。而一个具体的进程中至少要有一个线程运行,即主线程main。


2 线程建立

2.1 线程建立的方法一:继承Thread类,

2.1.1,定义一个类继承Thread类。Thread是线程的大类,拥有多种面向线程的操作方法,供子类运用。

2.1.2,覆盖Thread中的run(){}方法。用于存放该线程需要执行的内容。即该线程的“任务”

2.1.3,直接创建该类的实例对象,创建线程。

2.1.4,调用start方法开启该线程并调用线程的run执行任务。


class Day12
{
	public static void main(String[] args)
	{
		Demo t1 = new Demo(); //建立线程,但未启动
		t1.start(); //线程启动;
		Demo t2 = new Demo(); //建立线程2,
		t2.start(); //线程2启动
	}
}
class Demo extends Thread
{
	int x = 0;
	public void run(){	
		for (;x<= 10;x++){
			System.out.println(this.getName()+"..."+x);
		}
	}
}

Thread-1...0
Thread-0...0
Thread-1...1
Thread-0...1
Thread-1...2
Thread-0...2
Thread-1...3
Thread-1...4
Thread-0...3
Thread-1...5
Thread-0...4
Thread-0...5
Thread-0...6
Thread-1...6
Thread-0...7
Thread-0...8
Thread-0...9
Thread-0...10
Thread-1...7
Thread-1...8
Thread-1...9
Thread-1...10


①其中this.getName语句获取当前线程的线程名。

②每个线程都有系统默认的名字Thread-0,-1,...

③可以看到线程0和线程1的执行无序的。jvm是随机调用线程,会出现较长时间内只操作一个线程的情况。

④start语句执行,则获取了可运行状态,一旦线程获取了执行权,则自动调用run语句,执行”任务“。


而单线程:

class Day12{
	private String name;
	Day12(String name){this.name = name;}
	public static void main(String[] args){
		Day12 d = new Day12("zhangsan");
		Day12 d1 = new Day12("lisi");
		d.demo();
		d1.demo();
	}
	void demo(){
		for (int x= 1; x<=5; x++){
			System.out.println(name+"..."+x);
		}
	}
}

zhangsan...1
zhangsan...2
zhangsan...3
zhangsan...4
zhangsan...5
lisi...1
lisi...2
lisi...3


输出为语句顺序。d.demo()完成后它的”任务“循环后才执行d1.demo()。


2.2 线程建立的方法二:实现Runnable接口。

2.2.1,定义类实现Runnable接口。

2.2.2,覆盖接口中的run()方法,同方法一,储存线程要执行的任务。

2.2.3,通过Thread类创建的线程对象,并将Runnbale接口的子类对象(可以创建对象,或者用匿名对象)传入Thread类的构造函数里的参数中。

这是因为Thread类其中一个构造方法是输入Runnable作为参数。目的是让该Thread对象明确运行的内容。




















2.2.4,调用线程对象的start()方法开启线程。

class Day12{
	public static void main(String[] args){
		Demo d = new Demo();
		Thread t = new Thread(d);
		t.start();
		Thread t2 = new Thread(d);
		t2.start();
	}
}
class Demo implements Runnable{
	public void run(){
		for (int x=1; x<=10; x++){
			System.out.println(Thread.currentThread().getName()+"..."+x);
		}
	}
}

Thread-0...1
Thread-1...1
Thread-0...2
Thread-1...2
Thread-0...3
Thread-1...3
Thread-0...4
Thread-0...5
Thread-0...6

①Thread类自带getName()(返回Thread的名字,String类型)方法可以获取当前运行线程的名字(如方法一),但是方法二实现Runnable的时候并没有直接继承Thread这个”技能“,怎么输出名字?
可以想到,就算Runnable接口的子类Demo并不是继承Thread,它将来也必须被Thread类或其子类的实例调用(否则就没有存在的意义了)。那么此时可以用Thread的一个静态方法currentThread()获取”目前正在调用该语句的线程“,返回Thread类,然后再getName()一次,即可获得线程名字(String)并进行操作。所以有Thread.currentThread().getName()。

PS:使用实现Runnable接口来实现多线程的好处是,使用接口可以规避java父子类只能单继承的局限性(因为接口可以多实现,不妨碍该类在后续与其他类建立各种关系)。其次,实现Runnable可以讲线程的任务单独封装起来,脱离子类而独立成为对象。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值