程序,进程和线程
程序:一个可执行的文件
进程:一个正在运行的程序,也可以理解成在内存中开辟了一块儿空间
线程:负责程序的运行,可以看做一条执行的通道或执行单元,所以我们通常将进程的工作理解成线程的工作
进程中必须有线程,至少有一个。
单线程:当有一个线程的时候我们称为单线程(唯一的线程就是主线程)。
多线程:当有一个以上的线程同时存在的时候我们称为多线程。
多线程的作用:为了实现同一时间干多件事情(宏观上)。不能提高效率
任务区:我们将线程工作的地方称为任务区。每一个线程都有一个任务区,任务区通过对应的方法产生作用。
Java或者说JVM默认是多线程的,且至少要有两个线程:
主线程:任务区:main函数
垃圾回收线程:任务区:finalize函数
public class Demo {
public static void main(String[] args) {//有一个线程----主线程
new MyTest();//匿名对象---垃圾
/*
手动运行gc:垃圾回收器,运行垃圾回收机制
原理:当执行gc方法时,会触发垃圾回收机制,
开启垃圾回收线程,自动调用finalize方法
注意点:多个线程之间是抢cpu的关系,cpu有随机性.
*/
System.gc();//有两个线程,主线程和垃圾回收线程
System.out.println("main");
}//主函数结束,主任务区结束,线程随着任务的结束而结束,随着任务的开始而开始.
//当线程还在工作的时候,进程不能结束.
}
class MyTest{
//重写finlize方法
/*
正常情况下,这个函数是由系统调用的.重写它是为了观察多线程的实现
正常情况下,当MyTest的对象被释放的时候,会自动调用他的finalize方法
*/
protected void finalize() throws Throwable {
System.out.println("finalize");
}
}
Thread和Runnable
默认情况下,主线程和垃圾回收线程都是由系统创建的,但是我们需要完成自己的功能时就要创建自己的线程对象
Java将线程面向对象了,形成的类就是Thread,在Thread类内部执行任务的方法叫run()
注意:如果想让run作为任务区,必须让他去被自动调用。我们通过执行start()方法,来实现run方法的调用。否则就会作为所在线程的一个函数出现。
创建线程的三种情况:
First:
public class Demo {
public static void main(String[] args) {//两个,垃圾回收线程和主线程,但是一般先将垃圾回收线程忽略掉
//通过Thread类直接创建线程
Thread thread1 = new Thread();//创建了一个线程
Thread thread2 = new Thread();//创建了一个线程
//调用start(),开启线程
thread1.start();//两个
thread2.start();//三个
System.out.println("main");
}
}
Second:
public class Demo8 {
public static void main(String[] args) {
//通过Thread类的子类创建线程
MyThread thread1 = new MyThread("tan jie");//创建了一个线程 thread-0
MyThread thread2 = new MyThread("yi fei");//创建了一个线程 thread-1
//调用start(),开启线程
thread1.start();
thread2.start();
//主线程的系统名字是main
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" main i:"+i);
}
//手动调用run方法,他只是一个普通的方法,不能代表任务区,只有被自动调用的时候才是任务区
//手动调用时,调用run方法处的线程,就是run方法内部对应的线程.
thread1.run();
}
}
//写Thread类的子类,因为Thread类的run方法是空的,无法实现具体的任务,所以要通过创建子类的方式实现我们自己的功能
//作为Thread的子类也是线程类
class MyThread extends Thread{
String myname;
public MyThread(String myname) {
super();
this.myname = myname;
}
/*
*重写run()方法,---作为线程的任务区,完成我们的功能.
*Thread.currentThread():获取的是当前的任务区对应的线程
*getName():线程的名字
*/
public void run() {
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" run:"+myname+" i:"+i);
}
}
}
Third:
将任务从线程中分离出来,哪个线程需要工作,就将任务交给谁,操作方便。
/*
实例:四个售票员卖票
分析:创建4个线程---四个售票员
操作一份数据
*/
public class Demo {
public static void main(String[] args) {
//1.先创建任务类对象
Ticket ticket = new Ticket();
//2.创建线程对象,并将任务交给线程
//JavaApi中对Thread类run()方法的解释:
//如果该线程是使用独立的 Runnable 运行对象构造的,
//则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
//为了将任务和线程分离,java做了一个Runnable的接口
//实现了这个接口的类可以作为参数传给线程
//所以说明任务类中的run方法优先级高于Thread内部的run()
Thread thread1 = new Thread(ticket);
Thread thread2 = new Thread(ticket);
Thread thread3 = new Thread(ticket);
Thread thread4 = new Thread(ticket);
//3.开启线程
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
//创建任务类
class Ticket implements Runnable{
//所有的线程共享num
int num = 20;
public void run() {
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+" i:"+i+" "+ --num);
}
}
}
线程注意点:
Thread thread1 = new Thread();
Thread thread2 = new Thread(thread1);//将thread1当做任务处理了
thread1.start();//调用的是thread1的run()方法
thread2.start();//调用的是thread1的run()方法
//匿名子类对象也可以工作
new Thread(){
public void run() {
}
}.start();