Java基础_多线程1[线程引入及第一个多线程程序]


多线程

1.多线程的引入
如果程序只有一条执行路劲,那么该程序就是单线程程序。
如果有多条执行路劲,那么改程序就是多线程程序。

2.进程概述以及多进程意义
想要了解线程,必须先了解进程,因为线程是依赖于进程。

(1).什么是进程?
就是正在运行的应用程序。是系统进行资源分配和调度的独立单位。每一个进程都有它自己的内存空间和系统资源。

(2).多进程有什么意义?
我们看见一台电脑上面可以运行多个应用系统,但是我们可以看见可以有多个应用程序运行,也就是可以实现多进程,
如:边听音乐(音乐进程),边玩游戏(游戏进程)。也就是在一个时间段上可以执行多个进程。并提高cpu的使用率。


(3).一个细节问题?
一边玩游戏和一边听音乐是同时进行的吗?

同时进行的概念:表示在同一个时间的点(如秒,毫秒)上。

答:不是,这是不可能的,因为单个CUP在某一个时间点上只能够处理一件事情,而玩游戏和听音乐的时候是CUP是在做着CUP在程序之间进行
着高速的切换着,就让我们感觉是没有间断的。


3.线程
(1).什么是线程?
在同一个进程内又可以执行多个任务。而每一个任务,我们就可以看成是一个线程。
线程:是程序的执行单元,也叫执行路劲,也是程序使用CPU的最基本单元。


(2).单线程和多线程定义
单线程:如果程序只有一条执行路劲,那么就叫单线程。
多线程:如果程序有多条执行路劲,那么就叫多线程。

(3).多线程的存在意义
多线程的存在不是为了提高程序的执行速度,而是为了提高应用程序的使用率。
程序的执行都是在抢cpu的使用权,而多个进程是在抢这一个使用权的时候,如果说这一个进程的执行路劲比较多,就会有更高的几率抢到
CPU的执行权。尽管这样,我们还是无法保证哪一个线程能够哪一个时刻抢到CPU的使用权,所以线程的执行有随机性。


(4).并发和并行的区别
并发:表示的是物理上是同时发生,值的是在同一个时间点同时运行多个程序。
并行:表示的是逻辑上的同时发生,指的是在同一个时间内同时运行多个程序。


4.Java程序的运行原理和jvm的启动

(1).java程序的运行原理
Java命令会启动Java虚拟机,启动jvm,等于启动了一个应用程序,也即是启动了一个进程。那么该进程就会启动一个'主线程',然后
'主线程'再去调用类的mian()方法,所以main()方法是运行在主线程中的。在此之前的所有的程序都是单线程的。

(2).jvm的启动是多线程的吗?
是,原因是:至少有一个主线程,还要需要有一个垃圾回收线程,这是因为垃圾回收线程开始的时候就已经启动起来了,并实时监控着是否
有垃圾,当内存不够的时候就调用垃圾回收线程来回收垃圾,这也就是为什么java程序很少容易出现死机。



5.如何实现多线程以及多线程的实现方式1
(1).如何实现多线程?
由于线程是依赖于进程而存在,我们应该先创建一个进程出来,由于进程是系统创建出来的,所以我们应该去掉用系统的功能去创建一个
进程出来。
但是java语言是不能够直接调用系统功能的,所以我们没有办法直接实现多线程程序,但是Java可以去调用c/c++编写好的程序来实现
多线程,让c/c++去调用系统程序来创建一个进程,然后java去调用这样的东西,并让java去调用这样的东西并提供一些类供我们使用
这样,我们就可以使用java来实现多线程了。

(2).java提供的类是什么呢?
通过API,我们知道可以有俩种实现方法。

实现方法1:继承Thread类
实现步骤:
A.自定义类,继承Thread类
B.在自定义类中重写run()方法
为什么是run()方法呢?
C.创建自定义类对象。
D.启动线程。

问题1:为什么重写的是run()方法,而不是其他的方法呢?

根据继承的特性,我们在继承了Tread类以后我们就可以使用多线程,但是在我定义的方法中不是所有的代码都需要
被多线程执行,也就是说,我们只需要把我们代码里面需要被多线程执行的那一部分代码放到重新的run()方法里面
同时我们还可以有自己不被多线程执行的代码。

问题2:哪一些代码适合放置在run()方法里面呢?
一般需要被线程执行的代码都是比较繁琐的,也就是说会出现俩个再抢同一个东西这一种情况,以保证A在使用的时候
也能够让B在使用。


问题3:我们调用Thread里面的run()方法为什么还是单线程的呢?
代码:
MyThread mt =new MyThread();
mt.start();
mt.start();
该代码是有异常的,因为同一个线程mt被调用了俩次,会被抛出异常:IllegalTreadStateException:非法的线程状态异常
MyThread mt =new MyThread();
MyThread mt2 =new MyThread();
mt.start();
mt2.start();
这样才正确。

如果说我们直接这样去调用run()方法,这样的操作其实和我们去调用普通的方法是没有什么俩样的,所有你看到的是
单线程的效果。要想看到多线程的效果,我们就需要调用Thread的start()方法。
start()方法的俩个操作过程是:
A:使线程执行,
B:java 虚拟机调用该线程的run()方法

--->面试题:
Thread中run()和start()的区别?
run()仅仅只是封装被线程执行的代码,直接调用和一般的方法没有什么区别
start():首先启动了线程,然后使用jvm去调用该线程中的run()方法里面的代码。


注意事项:
在重新的run()方法里面调用的是super run();,也就是调用的是父类里面的方法,但是这样的操作是没有意思的,
我们在使用 到时候直接删掉就可以了。把我们需要在多线程中要执行的代码写在里面。

(3).一个多线程的简单代码实现:
public class MyThread extends Thread{

@Override
public void run() {

//super.run();
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}

//测试
public static void main(String[] args) {
MyThread mt =new MyThread();
MyThread mt1 =new MyThread();
mt.start();
mt1.start();
}
}
//效果(俩个线程在使用CPU时出现交叉,表明是一个多线程程序)
517
518
0
1


6.获取和设置线程对象名称

(1).public final String getName();获取该线程的名字
public final String setName(String name);设置该现成的名字


(2).输出的线程名称为什么默认是Thread-0/Thread-1这一种格式呢?
thread的无参构造源码:
class Thread{
public Thread(){
init(null,nill,"Threa-"+nextThreadNum(),0);
}
}

nextThreadNum()方法:
private static int threadinitNumber;//默认值是0
private static sychronized int nextThreadNum(){
return threadinitNumber++;//后++,先返回0
}

(3).如何获取main()方法线程对象的名称(用于获取针对不是Tread子类的对象名称。)
public static Thread CurrentTraed():获取当前正在执行的线程对象的名字


(4).代码实现:
public class MyThread extends Thread{
//方法2测试的时候需要提供该类的带参构造并传到父类上
public MyThread(String name) {
// TODO Auto-generated constructor stub
super(name);
}


@Override
public void run() {
//super.run();
for (int i = 0; i < 1000; i++) {
System.out.println(getName()+"---"+i);
}
}

//测试
public static void main(String[] args) {
//方法1
/*MyThread mt =new MyThread();
MyThread mt1 =new MyThread();
mt.setName("大猪");
mt1.setName("小猪");*/
//方法2
/*MyThread mt =new MyThread("大猪");
MyThread mt1 =new MyThread("小猪");
mt.start();
mt1.start();*/

//获取main方法的线程
System.out.println(Thread.currentThread().getName());
}

}

猜你喜欢

转载自www.cnblogs.com/nwxayyf/p/9568323.html
今日推荐