超牛牪犇Java之线程

一.进程和线程

进程:一个正在运行的程序就是一个进程

线程:一个线程中 有很多个线程(每一个线程相当于一个执行的任务)

CPU会随即在多个线程中进行切换 分时调度

CPU会在多个线程中进行随机切换

相当于在程序中进行快速切换(CPU运算很快)

开启一个线程 相当于开启了一个CPU的执行路径

CPU在执行多个线程的时候是随机的 跟线程的优先级有关

单线程程序的特点:

程序由上至下一次执行(一个执行完 才会去执行下一个)

好处:绝对安全 不牵扯到操作共享数据

弊端:效率不高

二.主线程

多线程的程序 除了主线程外 一般都叫子线程 且一个程序只有一个主线程

我们常用的main函数 就是一个线程 并且是主线程

主线程(叫main的线程)是如和被执行的

JVM调用main函数 --> CPU就为叫main的函数开辟了一个执行路径 --> 相当于在这个执行路径中 执行main函数中的代码

Thread 线程类 (可以开辟一个主线程以外的线程 子线程)

1.创建一个Thread类的子类

2.重写run方法

        run方法就是你要线程执行的代码

3.调用start方法 开启线程(不能重复开启)

例:

之前我们出现使用过的一个代码

public static void main(String[] args) {
    System.out.println(10/0);
}

 在报错时显示的是:

Exception in thread "main" 意思是异常出现在叫main的这个线程中

1.线程类

声明一个线程类

class SubTread extends Thread{
	//重写run方法
	@Override
	public void run() {
		//Exception in thread "Thread-0" 
		//子线程默认的名字  Thread-x
		//x是从0开始的
		System.out.println(10/0);
		//子线程 执行的代码
		for (int i = 0; i < 100; i++) {
			System.out.println("run---" + i);
		}
		System.out.println("我是子线程");
	}
}

在执行

System.out.println(10/0);

时,会报出一个异常Exception in thread "Thread-0"  

子线程默认的名字Thread-x x是从0开始的

在主线程中创建线程类对象 即创建一个子线程

public static void main(String[] args) {
        //开启多个线程时  多个线程 会同时执行
	//并且是相对的对立执行单元
	SubTread subTread = new SubTread();
	//开启
	subTread.start();
	SubTread subTread1 = new SubTread();
	subTread1.start();
		
	//主线程出现异常了 但是并没有影响子线程的执行
	System.out.println(10/0);
	for (int i = 0; i < 100; i++) {
		System.out.println("main---" + i);
	}
}
这里执行
System.out.println(10/0);

时,也会出现异常 但不会影响子线程的执行 说明主线程和子线程是相对独立的

三.线程的名字

在重写的run方法中

//在哪获取的就是哪个线程的对象
Thread currentThread = Thread.currentThread();
System.out.println("我是子线程" + currentThread.getName());

获取的就是重写这个run方法的子线程的名字

也可简写为:

System.out.println("我是子线程" + Thread.currentThread().getName());

如果直接在在主线程中写

Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName());

获取的就是当前正在执行的线程的名字 即主线程的名字


在主线程直接调子线程的run方法 相当于调用了一个普通的成员方法

而调用start方法 系统会开辟一个线程出来

练习:

创建一个线程类

类中有个name属性 并提供有参无参 set/get方法

class Mythread extends Thread{
	//定义了自己的name属性
	private String name;
	public Mythread() {
		
	}
	//有参的构造方法
	//1.给父类的name属性赋值
	//2.给本类的name属性赋值
	public Mythread(String name,String myName) {
		super(name);
		//给本类的name赋值
		this.name = myName;
	}
}

但是在写set/get方法时 会报错

因为在父类Thread类中使用了final修饰了该方法 不能被子类重写

所以需要改一下set/get的方法名(只要和默认名字不一样就可以) 来重新提供set/get方法

另外

创建一个线程相当于CPU开辟了一个独立的执行路径

相当于开辟了一个独立的方法栈区 来专门运行子线程中的方法

四.创建线程的方法二

用接口实现类的方式来创建

创建一个类 来实现Runnable接口

class RunnableImpl implements Runnable{
	//测试该方法能不能执行 是不是在子线程中执行
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + "--" + i);
		}
	}
}

在主线程中用创建接口的实现类的对象来创建子线程

RunnableImpl rImpl = new RunnableImpl();
//创建一个线程类对象
Thread thread = new Thread(rImpl);
//run方法不能开启线程 start方法才能开启线程
//thread.run();
thread.start();

可以把两步合起来写:

直接在主线程中创建:

Thread t = new Thread(new Runnable() {		
	@Override
	public void run() {
		System.out.println("子线程执行的方法");
	}
});

五.创建线程的方法三

匿名内部类的方式创建

匿名内部类创建出来的对象是该类的子类对象

接口和类都可以用这种方法

1.类
class Test{
	public void fun() {
		System.out.println("我是Test类中的fun方法");
	}
}

在主线程中用匿名内部方法创建线程的写法:

Test test = new Test() {
	//重写fun方法
	@Override
	public void fun() {
		System.out.println("我是匿名内部类中重写的fun方法");
	}
};
test.fun();

new Test() { };相当于是Test类的子类对象

并且在后面的大括号中 可以重写父类的方法

2.接口
interface TestInter{
	public abstract void fun();
	
}

直接创建接口类的实现类对象

TestInter testInter = new TestInter() {		
	@Override
	public void fun() {
		System.out.println("我是实现类的fun方法");
	}
};
testInter.fun();

也可以写成:

new TestInter() {		
	@Override
	public void fun() {
		System.out.println("我是实现类的fun方法");
	}
}.fun();

注意:这种方式 new后面跟的是父类名

但创建出来的对象 却是子类或实现类的对象

六.线程的休眠

测试线程代码时比较常用

线程的状态大致分为六种:

1.新建状态

        new thread()

2.运行状态

        start()

3.死亡状态

        run方法运行完毕的状态

        (也可以直接用stop方法进入此状态 不过已过时 不推荐用)

4.受阻塞状态

        线程调用了start方法 就一定进入运行状态吗?不一定!

        调用start方法是表示该方法可以被CPU执行 但是CPU不一定来执行此进程 所以不一定变成运行状态 需要等待CPU的执行

        这种状态叫做受阻塞状态

5.休眠状态

        sleep方法

        休眠结束 可能没有CPU执行 也可能进入受阻塞状态

6.等待状态

        wait方法进入等待状态

        notify方法可以唤醒线程

休眠:

主线程休眠是在主线程中调用sleep方法

参数是休眠时间 单位是毫秒

休眠时间结束 会自动醒来

Thread.sleep(1000);
System.out.println("aaaa");

子线程的休眠:

class TestA extends Thread{
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			//休眠
			//父类中的run没抛异常
			//子类就只能try/catch处理
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "--" + i);
		}
	}
}

在主线程中创建子线程

TestA testA = new TestA();
testA.start();
结果会让线程卡住1秒 再打印代码的内容
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值