java中的线程(线程\程序\进程、创建线程、图解多线程原理、Thread类中的方法、线程优先级)

线程

程序、进程、线程

概念

1、程序(program):为了完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码。

2、进程(process):正在执行的程序,从Windows角度讲,进程是含有内存和资源并安置线程的地方。

3、线程(thread):进程可进一步细化位线程,是一个进程内部的最小执行单元。简单理解就是进程中的一个任务,比如QQ中的一个聊天窗口就可以理解成一个线程。

线程和进程的关系

1、一个进程包含有多个线程,一个线程只能属于一个进程,线程不能脱离进程而独立运行。

2、每一个进程至少包含一个线程(即主线程);在主线程中开始执行程序,java程序的入口main()方法就是在主线程中被执行的。

3、在主线程中可以创建并启动其它线程。

4、一个进程内的所有线程共享该进程的内存资源。

多线程的概念

1、多线程是指程序中包含多个执行单元,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

2、何时需要多线程

(1)程序需要同时执行两个或多个任务;

(2)程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等;

(3)需要一些后台运行的程序时。

3、多线程的好处

(1)提高程序的响应;

(2)提高CPU的利用率;

(3)改善程序结构,将复杂任务分为多个线程,独立运行。

4、多线程的不利方面

(1)线程也是程序,所以线程需要占用内存,线程越多占用的内存就越多。

(2)多线程需要协调和管理,所以需要CPU跟踪线程;

(3)线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题。

创建线程

创建线程有两种方式,一种是继承Thread类的方式,另一种是实现Runnable接口的方式。

继承Thread类

1、在Java中要实现线程,最简单的方法就是扩展Thread类,重写其中的run方法,方法原型如下:

//创建
class PrimeThread extends Thread {
	long minPrime;
	PrimeThread(long minPrime) {
	this.minPrime = minPrime;
	}

	public void run() {
	// compute primes larger than minPrime
	. . .
	}
}
//以下代码将创建一个线程并启动它运行: 
PrimeThread p = new PrimeThread(143);
     p.start();

2、Thread类中的run方法本身并不执行任何操作,如果我们重写了一个run方法,当线程启动时,它将执行run方法。

代码示例—创建一个线程,随机性的打印结果。

public class Preview1 {
    
    
    /*这是一个程序入口*/
    public static void main(String[] args) {
    
    
        //创建thread类的子类对象
        PrimeThread p = new PrimeThread();
        //调用thread类中的方法start方法,开启新的线程,执行run方法
        /*
        * start()方法:开启新的线程,JVM执行run方法
        * 结果是两个线程并发地运行
        * 多次启动一个线程是非法的,特别是当线程已经完成任务后,不能重新启动
        */
        p.start();

        //mian()方法或者说主线程会继续执行主线程中的代码
        for (int i = 0; i < 10; i++) {
    
    
            System.out.println("Main:"+i);
        }
    }
}

//创建一个Thread类的子类
class PrimeThread extends Thread {
    
    
    //重写Thread类中的run方法,你让它做什么都可以写(即设置线程任务)
    @Override
    public void run() {
    
    
        for (int i = 0; i < 10; i++) {
    
    
            System.out.println("primethread:" + i);
        }
    }
}

代码示例的运行结果

Main:0
primethread:0
Main:1
primethread:1
Main:2
primethread:2
primethread:3
primethread:4
.....
Main:7
Main:8
Main:9

省略了中间的一部分(节省篇幅),但是很显然,上面代码示例的运行结果是无序的,证明CPU并不是按照我们所想的顺序去执行这一段代码。这里就要说到:java属于抢占式的调度,哪个线程优先级高,先执行哪个线程,同一个优先级,随机执行。

实现Runnable接口

1、java.lang.Runnable接口中仅仅只有一个抽象方法:

public void run();

2、实现Runnnable接口,实现run()方法可以创建线程。

3、Runnable接口的存在就是解决了java中不允许多继承的问题。

4、由于Runnable()接口中没有start()方法,因此不能直接运行,需要将其封装到Thread类中。

代码示例

public class Preview2 {
    
    
    /*这是一个程序入口*/
    public static void main(String[] args) {
    
    
        //创建实现Runnable接口的子类的对象
        MyThread m = new MyThread();
        //将子类对象封装到一个线程中
        Thread t = new Thread(m);
        //调用Thread类中的start()方法
        t.start();
        for (int i = 0; i < 10; i++) {
    
    
            System.out.println("Main:"+i);
        }
    }
}

//创建一个实现Runnable接口的类
class MyThread implements Runnable {
    
    
    //重写接口中的run方法,你让它做什么都可以写(即设置线程任务)
    @Override
    public void run() {
    
    
        for (int i = 0; i < 10; i++) {
    
    
            System.out.println("MyThread:"+i);
        }
    }
}

图解多线程原理

以 继承Thread类 中的代码示例为图解样例

在这里插入图片描述

多线程的内存原理图

创建线程两种方式的区别

1、区别

(1)继承Thread类:线程代码放在Thread子类的run()方法中;

(2)实现Runable接口:线程代码存放在接口的子类的run方法中。

2、实现Runnable接口的好处

(1)避免了单继承的局限性,因为一个类只能继承一个类,如果类继承了Thread类就不能继承其它的类。

(2)增强了程序的可扩展性,降低了程序的耦合性,实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离,创建Thread类对象,调用start()方法就只用来开启新线程。

Thread类中的方法

构造方法

方法 说明
Thread() 创建一个线程
Thread(String name) 创建一个指定名称的线程
Thread(Runnable target) 利用Runnable对象创建一个线程
Thread(Runnable target,String name) 利用Runnable对象创建一个线程,并命名

常用方法

返回值 方法名 功能
void start() 启动线程
final void setName(String name) 设置线程名称
final String getName() 返回线程名称
final void setPriority(int newPriority) 设置线程优先级
final int getPriority() 返回线程优先级
final void join() 等待线程终止
sattic Thread currentThread() 返回正在执行的线程对象引用
static void sleep(long millis) 让当前正在执行的线程休眠,指定时间,单位ms

代码示例

public class Preview3 {
    
    
    /*这是一个程序入口*/
    public static void main(String[] args) {
    
    
        MyThreadDemo myThreadDemo = new MyThreadDemo();
        myThreadDemo.start();//Thread-0  Thread[Thread-0,5,main]
        MyThreadDemo myThreadDemo1 = new MyThreadDemo();
        myThreadDemo1.start();//Thread-0  Thread[Thread-1,5,main]
        //在构造方法中改名
        MyThreadDemo myThreadDemo2 = new MyThreadDemo("狗子");
        myThreadDemo2.start();//狗子 Thread[狗子,5,main]

        MyThreadDemo1 my = new MyThreadDemo1();
        my.start();
    }
}

//创建一个集成Thread类的子类
class MyThreadDemo extends Thread{
    
    
    public MyThreadDemo(){
    
    }
    public MyThreadDemo(String name){
    
    
        //传给父类,让父类改名字去
        super(name);
    }
    @Override
    public void run(){
    
    

        //setName(String name)设置线程名称
//        setName("子线程");

        //getName()获取线程名称,返回String name
        System.out.println(getName());

        //currentThread()返回正在执行的线程对象引用
        Thread thread = Thread.currentThread();
        System.out.println(thread);
    }
}

class MyThreadDemo1 extends Thread{
    
    
    @Override
    public void run(){
    
    
        //模拟一个秒表
        for (int i = 1; i <= 20; i++) {
    
    
            System.out.println("第"+i+"秒");
            //sleep(long millis)让当前正在执行的线程休眠,指定时间,单位ms,睡眠完成后继续执行
            try {
    
    
                Thread.sleep(1000);//1000毫秒==1秒
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

线程优先级

概述

1、由于计算机只有一个CPU,各个线程轮流获得CPU的使用权,才能执行任务。

2、优先级较高的线程有更多获得CPU的机会,即抢夺CPU的执行权。
3、优先级用整数表示,取值范围是1~10,数字越大代表优先级越高,一般情况下,线程的默认优先级都是5,但是也可以通过setPriority和getPriority方法来设置或者返回优先级。

4、调度策略

(1)时间片

(2)抢占式:高优先级的线程抢占CPU

5、Java的调度方法

(1)同优先级线程组成先进先出队列(先到先服务),使用时间片策略。

(2)对于高优先级而言,使用优先调度的抢占式策略。

6、线程优先级的缺陷——线程优先级高度依赖于系统,比如,在windows系统中,有7个优先级级别,但在java中有10个优先级级别,不能做到一一对应,这就意味着至少会有两个优先级共享相同的windows操作系统优先级,而在Oracle为Linux提供的java虚拟机中,线程的优先级直接被忽略,所有线程的优先级相同,因此,不要过度以来优先级。

线程优先级的设置

1、setPriority()更改此线程优先级。

2、getPriority()返回次线程优先级。

3、Thread类有如下三个静态常量来表示优先级

(1)MAX_PRIORITY:取值为10,表示最高优先级。

(2)MIN_PRIORITY:取值为1,表示最低优先级。

(3)NORM_PRIORITY:取值为5,表示默认的优先级。

代码示例

public class PriorityDemo{
    
    
    /*这是一个程序入口*/
    public static void main(String[] args) {
    
    
        /*创建集成Thread类的线程对象*/
        MyThread4 my = new MyThread4();
        /*设置线程名称*/
        my.setName("线程0");
        /*设置线程优先级,低到高,1-10*/
        my.setPriority(Thread.MIN_PRIORITY);
        /*调用Thread类的start方法启动线程*/
        my.start();

        MyThread4 my1 = new MyThread4();
        my1.setName("线程1");
        my1.setPriority(6);
        /*调用Thread类的start方法启动线程*/
        my1.start();

        MyThread4 my2 = new MyThread4();
        my2.setName("线程2");
        my2.setPriority(Thread.MAX_PRIORITY);
        /*调用Thread类的start方法启动线程*/
        my2.start();

        /*主线程的任务,与另一线程并行执行*/
        for (int i = 0; i < 20; i++) {
    
    
            System.out.println(Thread.currentThread()+":"+i);
        }
    }
}

//创建一个集成Thread类的子类
class MyThread4 extends Thread {
    
    
    //重写Thread类中的run方法,是需要执行的线程任务
    @Override
    public void run() {
    
    
        for (int i = 0; i < 20; i++) {
    
    
            System.out.println(Thread.currentThread()+":" + i);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Lotus_dong/article/details/111202537