//程序就是[可执行]的文件
//程序运行起来就是一个进程
//线程是进程的最基本单位
//只要有进程,就最少有一个线程
//CPU在线程上干活
/*
* 多线程:
*
* 程序:是一个可执行的文件.
* 进程:是一个正在运行的程序.在内存中开辟了一块儿空间
* 线程:负责程序的运行,可以看做程序运行的一条通道或者一个执行单元.所以我们通常将进程的工作理解成线程的工作.
*
* 进程中可不可以没有线程? 必须有线程,至少有一个,当有一个线程存在的时候,我们称为单线程,这个唯一的线程就是主线程(main线程)
* 当有两个及讲个个以上的线程存在的时候,我们称为多线程.
*
* 多线程存在的意义:为了实现同一时间做多件事情.
*
* 任务区:我们将线程完成工作的方法称为任务区。其实任务区就是run()方法
* 每一个线程都有自己的任务区
*
* JVM是多线程吗?
* 一定是多线程
* 至少有两个
* 主线程的任务区:main方法
* 垃圾回收线程的任务区:finalize()方法
*/
public class Demo7 {
public static void main(String[] args)//--有一个线程:主线程
{
new MyTest();//匿名对象---垃圾
/*
* 手动运行gc:垃圾回收器,运行垃圾回收机制。
*
* 原理:当执行gc方法时,会触发垃圾回收机制,开启垃圾回收线程,自动调用finalize方法
*/
//注意点:多个线程之间是抢cpu的关系,cpu有随机性
System.gc();//有两个线程
System.out.println("main");
}//主函数结束,主任务区结束,线程随着任务的结束而结束,随着任务的开始而开始,
//main()相当于打开主线程,并运行里面的程序(任务)
//当线程还在工作的时候,进程不能结束
}
class MyTest{
//重写finalize
/*
* 正常情况下,这个函数是由系统自动调用的,重写它是为了观察多线程的实现
* 正常情况下,当MyTest的对象被释放的时候,会自动调用他的finalize方法
*/
protected void finalize()throws Throwable{
//正常的这里其实有父类的方法...进行垃圾回收
System.out.println("finalize");
}
}
/*
* 默认情况下,主线程和垃圾回收线程都是由系统创建的,但是我们需要完成自己的
* 功能---所以要创建自己的线程对象。
* java将线程面向对象了,形成的类就是Thread,在Thread类内部执行任务的方法叫run()
* 注意:如果想要run作为任务区,必须让他去被自动调用,我们通过执行start方法,来实现run()方法的调用
* 其实调用start()方法相当于打开这个线程,start方法会自动调用run()方法,相当于在该线程上跑任务(run方法内的程序)
*/
public class Demo8 {
public static void main(String[] args) {//两个。垃圾回收线程和主线程,
//注:一般会将垃圾回收线程忽略掉
// //1.通过Thread类直接创建线程
// Thread中的run()里并没有任何代码
// Thread t1=new Thread();
// Thread t2=new Thread();
// //调用start(),开启线程
// t1.start();//此时有两个线程
// t2.start();//此时有三个线程
// System.out.println("main");
//2通过Thread类的子类创建线程
MyThread t1=new MyThread("xiaote");//创建了一个线程 thread-0
MyThread t2=new MyThread("xiaosan");//创建了一个线程 thread-1
//调用start(),开启线程
t1.start();//此时有两个线程
t2.start();//此时有三个线程
System.out.println("main");
for(int i=1;i<=10;i++) {
System.out.println(Thread.currentThread().getName()+" "+" i: "+i);
}
//手动调用run方法,它只是一个普通的方法,没有开启线程,只是在主线程中跑完了run方法里的内容
t1.run();
}
}
//写 Thread类的子类,因为Thread类的run()方法是空的,无法实现具体的任务,
//所以用创建子类的方式去实现我们自己的功能,作为Thread子类也是线程类
class MyThread extends Thread{
String myname;
/*
* 重写run()方法作为线程的任务区,完成我们的功能
* Thread.currentThread()获取的是当前的任务区所在线程的对象
* getName():获取线程的名字
*/
public MyThread(String myname) {
this.myname=myname;
}
public void run() {
for(int i=1;i<=10;i++)
{
System.out.println(Thread.currentThread().getName()+" "+myname+" i: "+i);
}
}
}
//------下面两个例子还没有弄好
/*
* 实例:四个售票员卖票
* 分析:创建4个线程--四个售票员
* 一份数据
* 实现多线程的两种方式:
* 第一种方式:通过创建Thread子类的方式实现功能---线程与任务绑定在了一起
* 第二种:将任务从线程中分离出来,哪个线程需要工作,就将任务交给谁,操作方便
*
*/
//第一种方式:通过创建Thread子类的方式实现功能---线程与任务绑定在了一起
public class Demo9 {
public static void main(String[] args) {
// //创建四个线程
// Seller s1=new Seller();
// Seller s2=new Seller();
// Seller s3=new Seller();
// Seller s4=new Seller();
//
// //开启线程
// s1.start();
// s2.start();
// s3.start();
// s4.start();
//第二种:将任务从线程中分离出来
//1先创建任务类对象
Ticket ticket=new Ticket();
//2创建线程对象,并将任务交给线程
Thread t1=new Thread(ticket);
//里面自带一个run()然后Ticket里也有一个run()
//如果有Runnble的run方法,就会执行Runnale的run方法
//没有Thread中的里面什么都没有的run()方法
//所以说明任务类中的run方法优先级高于Thread内部的run()
Thread t2=new Thread(ticket);
Thread t3=new Thread(ticket);
Thread t4=new Thread(ticket);
//3开启线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//创建任务类
class Ticket implements Runnable{
//所有的对象共享num
int num=40;
@Override
public void run() {
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName()+" "+i+" "+(--num));
}
}
}
//创建Thread的子类
//class Seller extends Thread{
// //所有的对象共享num
// static int num=20;
// public void run() {
// for(int i=0;i<5;i++) {
// System.out.println(Thread.currentThread().getName()+" "+i+" "+(--num));
// }
// }
// }
public class Demo10 {
public static void main(String[] args) {
//线程的其他知识点
//1
Thread t1=new Thread();
Thread t2=new Thread(t1);
//将t2当做任务处理了,因为Thread实现了Runable接口
t1.start();//调用的是t1的run()方法
t2.start();//调用的也是t1的run()方法
//2匿名子类对象也可以工作
new Thread();//匿名对象
new Thread() {
public void run() {}
//这里重写了run()但其实Thread类本身里面就有run(){}
}.run();//匿名子类对象,该对象的父类是Thread
//直接调用run()没有用开启线程,这里run()就是普通的方法
//正确的方式:
new Thread() {
public void run() {}
//这里重写了run()但其实Thread类本身里面就有run(){}
}.start();
}
}