进程与线程:
Dos系统有一个非常明显的特点,只要种病毒之后则系统会立刻死机,因为dos系统采用的时单进程的处理方式,所以只能有一个独立运行的程序,其他程序无法运行:
windows系统中,即使出现了病毒,系统也可以正常运行,因为windows中采用的时多进程的处理方式,那么在同一个时间段,可以有多个程序运行:
如果一个进程没有了,则线程一定消失,如果线程消失了。那么进程未必会小时,而且,所有的线程都在进程的基础之上:
进程和线程,
进程是程序的一次动态执行过程,它经历了从代码加载,执行到执行完毕的完整的过程,这个过程也是进程本身从产生,发展到最终消亡的过程:
多线程是实现并发机制的一种手段,进程和线程一样,都可以实现并发的一个基本单位:
图片:
如果现在同时运行多个任务,则所有的系统资源都是共享的,被所有线程公用,但是程序处理需要CPU,传统的单核CPU来说,在同一个时间段上会有多个程序执行,但是在同一个时间点上只能存在一个程序运行,也就是说,所有的程序都要抢占CPU资源。
但是现在的cpu已经发展到多核状态,在一个电脑上可能存在多个CPU,那么这个时候就可以非常清楚的发现多线程操作键是如何进行并发执行的。
JAVA的多线程的实现:
如果在JAva中想要实现多进程,可以采用一下两种方式:
- 继承Thread类
- 实现Runable接口:
- Thread类:
- Thread类是在Java.lang 包中定义的,只要一个类集成了Thread类,此类就称为多线程的操作类:在Thread子类中,必须明确覆写,Thread类中的run()方法: 此类方法为线程的主题。
多线程的定义语法:
class 类名称 extends Thread {
覆写Thread 类中的Run方法:
punlic void run{
}
}
Java代码示例:
- class MyThread extends Thread{ // 继承Thread类,作为线程的实现类
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + “运行,i = ” + i) ;
}
}
};
public class ThreadDemo01{
public static void main(String args[]){
MyThread mt1 = new MyThread(“线程A “) ; // 实例化对象
MyThread mt2 = new MyThread(“线程B “) ; // 实例化对象
mt1.run() ; // 调用线程主体
mt2.run() ; // 调用线程主体
}
};
图片:运行结果:
以上程序是先执行A后在执行B,并没有达到所谓的并发执行的效果:
因为以上程序实际上时按照古老的形式调用,通过对象方法,但是,如果想要启动一个线程必须使用Thread类中的start方法。
一旦调用start方法。实际上最终调用的就是run方法:
Java代码:- class MyThread extends Thread{ // 继承Thread类,作为线程的实现类
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + “运行,i = ” + i) ;
}
}
};
public class ThreadDemo02{
public static void main(String args[]){
MyThread mt1 = new MyThread(“线程A “) ; // 实例化对象
MyThread mt2 = new MyThread(“线程B “) ; // 实例化对象
mt1.start() ; // 调用线程主体
mt2.start() ; // 调用线程主体
}
};
运行结果:线程A运行,i = 0
线程A运行,i = 1
线程A运行,i = 2
线程B 运行,i = 0
线程B 运行,i = 1
线程A运行,i = 3
线程B 运行,i = 2
线程B 运行,i = 3
线程B 运行,i = 4
线程B 运行,i = 5
线程A运行,i = 4
线程B 运行,i = 6
线程B 运行,i = 7
线程A运行,i = 5
线程A运行,i = 6
线程A运行,i = 7
线程A运行,i = 8
线程A运行,i = 9
线程B 运行,i = 8
线程B 运行,i = 9
从此处的效果来看,确实是并发执行了,那个线程先抢到CPU资源,那个线程就先执行:
那么问题来了:为什么不直接调用run()方法,而是调用start()方法呢?
如果想要解决这个问题那么我们一定要看源码:
public synchronized void start() {
/**
* This method is not invoked for the main method thread or “system”
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state “NEW”.
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group’s list of threads
* and the group’s unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();
Native关键字,表示的是一个由Java调用本机操作系统的一个关键字,在Java中,运行Java程序调用本机的操作系统的函数以完成特定的功能:
证明: 如果现在要是想实现多线程的的话,则坑顶需要操作系统的支持,因为多线程操作中牵扯到一个抢占CPU的情况;要等待CPU进行调度,那么这一点坑顶需要操作系统的底层的支持,所以使用了Native调用了本机的系统函数,而且各个操作系统中多线程的底层实现代码肯定不同,所以使用native关键字也可以让JAM自动的调整不同的JVM的实现:
ThreadStatus 也表示一种装状态,如果线程已经启动,在调用start方法的时候,就有可能产生异常:
Java代码:
public class MyThread{
public static void main(String args[]){
MyThread1 mt1 = new MyThread1(“线程A”); // 实例化对象
// MyThread1 mt2 = new MyThread1(“线程B “) ; // 实例化对象
mt1.start() ; // 调用线程主体
mt1.start() ; // 调用线程主体
}
};
class MyThread1 extends Thread{ // 继承Thread类,作为线程的实现类
private String name ; // 表示线程的名称
public MyThread1(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + “运行,i = ” + i) ;
}
}
};
运行结果:
图片:
##实现Runable接口:
在Java中也可以通过实现Runable接口的方式实现多线程,Runable接口中只定义了一个抽象方法:
- public void run();
通过Runable 接口实现多进程:
- class 类的名称 implements Runable{//实现Runable接口
属性:
方法:
public void run(){
//线程主题
}
}
Java代码
class MyThread implements Runnable{ // 实现Runnable接口,作为线程的实现类
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + “运行,i = ” + i) ;
}
}
};
public class RunnableDemo01{
public static void main(String args[]){
MyThread mt1 = new MyThread(“线程A “) ; // 实例化对象
MyThread mt2 = new MyThread(“线程B “) ; // 实例化对象
Thread t1 = new Thread(mt1) ; // 实例化Thread类对象
Thread t2 = new Thread(mt2) ; // 实例化Thread类对象
t1.start() ; // 启动多线程
t2.start() ; // 启动多线程
}
};
注意: 如果想要启动线程则肯定依靠Thread类,但是之前如果直节继承,Thread 类,则直解继承下来并使用,但是在Ruanble接口中没有此方法:
Thread类的构造:
- public Thread(Runnable target);
利用此方法启动多线程:
Thread类和Ruannble接口的联系:
Thread定义:
- public class Thread extends Object implements Runnable
从定义格式上可以发现,Thread 类也是Ruanble的子类
Thread类和Ruannble接口的区别:
使用Thread类操作多线程的时候无法达到资源的共享目的。而使用Ruanble接口实现的多线程操作可以实现资源的共享。
Thread 代码:
class MyThread extends Thread{ // 继承Thread类,作为线程的实现类
private int ticket = 5 ; // 表示一共有5张票
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<100;i++){
if(this.ticket>0){
System.out.println(“卖票:ticket = ” + ticket–) ;
}
}
}
};
public class ThreadDemo04{
public static void main(String args[]){
MyThread mt1 = new MyThread() ; // 实例化对象
MyThread mt2 = new MyThread() ; // 实例化对象
MyThread mt3 = new MyThread() ; // 实例化对象
mt1.run() ; // 调用线程主体
mt2.run() ; // 调用线程主体
mt3.run() ; // 调用线程主体
}
};
结果:
发现一共卖了15张票,证明,3个线程各自卖了5张票,也就是说没有达到资源共享的目的:
Ruannable 代码:
class MyThread implements Runnable{ // 继承Thread类,作为线程的实现类
private int ticket = 5 ; // 表示一共有5张票
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<100;i++){
if(this.ticket>0){
System.out.println(“卖票:ticket = ” + ticket–) ;
}
}
}
};
public class RunnableDemo02{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 实例化对象
new Thread(mt).run() ; // 调用线程主体
new Thread(mt).run() ; // 调用线程主体
new Thread(mt).run() ; // 调用线程主体
}
};
从运行效果来看,3个线程一共卖了5张票,达到了资源的共享:
Thread 类与Runnable接口的使用结论
实现Ruannable 接口比继承Thread类有如下明显的优点。
- 时候多个相同的程序代码的线程处理同一个资源
- 可以避免单继承局限带来的影响:
- 增强了程序的健壮性,代码能过被多个线程共享: