java线程(一)

线程(执行代码)

进程:代表了内存中正在运行的应用程序

线程:线程是进程中的一个代码执行单元,负责当前进程中代码程序的执行,一个进程中有一个或多个线程。 当一个进程中启动了多个线程去分别执行代码的时候,这个程序就是多线程程序。

并发和并行
线程的并发执行,是指在一个时间段内,俩个或多个线程,使用一个CPU,进行交替运行。(问题主要出在这,我们解决的就是这个并发)在这里插入图片描述

线程的并行执行,是指在同一时刻,俩个或多个线程,各自使用一个CPU,同时进行运行。
在这里插入图片描述
如果计算机是单核CPU的话,那么同一时刻只能有一个线程使用CPU来执行代码

如果计算机是多核CPU的话,那么同一时刻有可能是俩个线程同时使用不同的CPU执行代码

时间片

时间片,当前一个线程要使用CPU的时候,CPU会分配给这个线程一小段时间(毫秒级别),这段时间就叫做时间片,也就是该线程允许使用CPU运行的时间,在这个期间,线程拥有CPU的使用权。
如果在一个时间片结束时,线程还在运行,那么这时候,该线程就需要停止运行,并交出CPU的使用权,然后等待下一个CPU时间片的分配。

在宏观上,一段时间内,我们感觉俩个线程在同时运行代码,其实在微观中,这俩个线程在使用一个CPU的时候,它们是交替着运行的,每个线程每次都是运行一个很小的时间片,然后就交出CPU使用权,只是它们俩个交替运行的速度太快了,给我们的感觉,好像是它们俩个线程在同时运行。

调度
当俩个或多个线程使用一个CPU来运行代码的时候,在操作系统的内核中,就会有相应的算法来控制线程获取CPU时间片的方式,从而使得这些线程可以按照某种顺序来使用cpu运行代码,这种情况被称为线程调用。

常见的调度方式:

时间片轮转

所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。

抢占式调度(大部分/jvm)

系统会让优先级高的线程优先使用 CPU(提高抢占到的概率),但是如果线程的优先级相同,那么会随机选择一个线程获取当前CPU的时间片。

main线程
使用 java 命令来运行一个类的时候,首先会启动JVM(进程),JVM会在创建一个名字叫做main的线程,来执行类中的程序入口(main方法)

public class Test {
    public static void main(String[] args) {
        //获取执行当前方法的线程对象
        Thread currentThread = Thread.currentThread();
        System.out.println("执行当前方法的线程名字为:"+currentThread.getName());
    }
}
//运行结果:
执行当前方法的线程名字为:main

Thread.currentThread(); 可以写在任意方法中,返回就是执行这个方法的线程对象

线程类

java.lang.Thread

java.lang.Thread 是java中的线程类,所有的线程对象都必须是Thread类或其子类的实例。

每个线程的作用,就是完成我们给它指定的任务,实际上就是执行一段我们指定的代码。我们只需要在Thread 类的子类中重写 run 方法,把执行的代码写入到run方法中即可,这就是线程的执行任务!

Java中通过继承Thread类来创建并启动一个新的线程的步骤如下:

  1. 定义 Thread 类的子类(可以是匿名内部类),并重写 Thread 类中的 run 方法, run 方法中
    的代码就是线程的执行任务
  2. 创建 Thread 子类的对象,这个对象就代表了一个要独立运行的新线程
  3. 调用线程对象的 start 方法来启动该线程
    在这里插入图片描述
public class ThreadTest {

	public static void main(String[] args) {
		System.out.println("main start");
		
		Thread t = new Thread() {
			@Override
			public void run() {
				for (int i = 1; i <=100; i++) {
					System.out.println(getName()+"i:"+i);
				}
			}
		};//创建进程对象
		t.start();//启动对象
		Thread t1 = new Thread() {
			@Override
			public void run() {
				for (int i = 1; i <=100; i++) {
					System.out.println(getName()+"i:"+i);
				}
			}
		};
		t1.start();
		for (int i = 1; i <=100; i++) {
			System.out.println("main i:"+i);
		}
		System.out.println("main end");

	}

}

在这里插入图片描述
结果如上,可以看出三个线程互相抢夺

Runnable接口

给一个线程对象指定要执行的任务,除了继承Thread类后重写run方法之外,还可以利用Runnable接口来完成线程任务的指定

Thread 类也是 Runnable 接口的实现类,其代码结构大致为

public class Thread implements Runnable {
    /* What will be run. */
    private Runnable target;
    	public Thread() {
   	 	//...
	}
    public Thread(Runnable target) {
        this.target = target;
        //..
    }
    @Override
    public void run() {
        if (target != null) {
        	target.run();
        }
    }
}

可以看出,子类重写Thread中的run方法,这个run方法其实也来自于Runnable接口

使用 Runnable 接口的匿名内部类,来指定线程的执行任务(重写接口中的run方法)

public class Test {
    public static void main(String[] args) {
        //Runnable接口的实现类中,重写了run方法,指定线程的执行任务
        Runnable run = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("hello world");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            	}
        	}
        };
            //创建线程对象,指定执行任务
            Thread t = new Thread(run);
            t.start();
    }
}

实现Runnable接口比继承Thread类所具有的优势:

  1. 可以把相同的一个执行任务(Runnable接口的实现),交给不同的线程对象去执行
  2. 可以避免java中的单继承的局限性。
  3. 线程和执行代码各自独立,实现代码解耦

线程(二)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值