欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java多线程机制(一)

程序员文章站 2022-05-04 19:26:59
...

Java多线程机制

一、线程的基本概念

  1. 概念: 线程是一个程序内部的顺序控制流
  2. 线程和进程区别:
    (1)每个进程都有独立的代码和数据空间,进程间的切换会有较大的开销。
    (2)线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。
    (3)多进程:在操作系统中能同时运行多个程序。
    (4)多线程:在同一个应用程序中有多个顺序流同时执行。
    (5)通俗的说,线程是一个进程里面不同的执行路径,一个进程里面有一个主线程就是main()方法。进程是一个静态的概念,在我们计算机内部实际运行的都是线程。
  3. Java的线程是通过java.lang.Thread类来实现的。虚拟机启动时会有一个由主方法,也就是main方法所以定义的线程。可以通过创建Thread的实例来创建新的线程。每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。
  4. 三个原则:
    (1)什么是进程?进程是一个静态的概念。
    (2)什么事线程?一个进程里面有一个主线程main()方法,是一个程序里面、一个进程里面的不同的执行路径。
    (3)在同一个时间点上,一个CPU只能支持一个线程在执行,如果机器是双CPU或者是双核,则支持多线程。

二、线程的创建和启动

两种方式创建和启动新的线程,无论使用哪种方式创建线程,线程的启动都必须调用Thread类的start()方法。原则:只要能使用接口就不用从Thread类继承

  1. 第一种,定义线程类实现Runnable接口
Thread myThread = new Thread(target) //target为runnable接口类型
//Runnable中只有一个方法:
public void run(); //用于定义线程运行体

使用Runnable接口可以为多个线程提供共享数据。在实现Runnable接口的类的run()方法定义中可以使用Thread的静态方法pulic static Thread currentThread() //获取当前线程的引用

  1. 第二种,可以定义一个Thread的子类并重写其run方法,示例:
class MyThread extends Thread{
	public void ruan(){......}
}
//生成该类的对象
MyThread myThread = new MyThread(...);

示例1:

package threadtest;

public class TextThread1 {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runner1());
        thread1.start();
        for (int i = 0; i < 60; i++) {
            System.out.println("Main   " + i);
        }
    }
}

//通过实现Runnable接口开启线程
class Runner1 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 60; i++) {
            System.out.println("Runner1   " + i);
        }
    }
}

输出结果:
Java多线程机制(一)
可以看到,main方法和run方法交替运行或者说是并行运行。
示例2:

package threadtest;

public class TextThread1 {
    public static void main(String[] args) {
       Runner1 runner1 = new Runner1();
       runner1.start();
        for (int i = 0; i < 60; i++) {
            System.out.println("Main   " + i);
        }
    }
}
//通过继承Thread类开启线程
class Runner1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 60; i++) {
            System.out.println("Runner1   " + i);
        }
    }
}

Java多线程机制(一)
可以看到和上面的输出方式是一样的,Main方法和run方法交替运行。

三、线程状态转换

Java多线程机制(一)
1.当new一个Thread,线程就已经创建了,然后进入就绪状态,当cpu分配给线程时间片,此时该线程进入运行状态,当时间片用完线程又进入就绪状态,然后在分配时间片给线程,如此循环,最终线程终止。
2.线程在运行过程中有可能发生意外导致线程进入阻塞状态,意外接触后,线程进入就绪状态,然后执行过程如上面地说明。

四、线程控制的基本方法

Java多线程机制(一)

  1. sleep方法
    属于静态方法,可以调用Thread类的静态方法public static void sleep(long millis) throws InterruptedException 使得当前线程休眠,也就是暂停当前线程执行millis毫秒。在哪个线程里面sleep方法就让哪个线程睡眠。由于sleep是静态方法,sleep可以由类名直接调用,Thread.sleep(…)。注意:stop方法已经弃用!

示例:仅作为示例学习,不建议直接使用interrupt结束线程

package threadtest;

import java.util.Date;

public class TestInterrupt {

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        try {
            //主线程睡眠五秒钟
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //结束子线程
        myThread.interrupt();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
    	//每隔一秒打印一次当前时间
        while (true) {
            System.out.println("-------" + new Date() + "----------");
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                return;
            }
        }
    }
}

执行结果:
Java多线程机制(一)

  1. join方法,合并某个线程,合并的线程执行结束,再开始执行当前线程。
package threadtest;

public class TextJoin {

    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2("myThread2");
        myThread2.start();
        try {
        	//合并myThread2线程
            myThread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println("i am main thread");
        }
    }
}

class MyThread2 extends Thread {
    MyThread2(String s) {
        super(s);
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("i am " + getName());
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                return;
            }
        }
    }
}

执行结果:
Java多线程机制(一)

  1. yield方法,让出CPU,给其他线程执行的机会
    示例:
package threadtest;

public class TestYield {
    public static void main(String[] args) {
        MyThread3 t1 = new MyThread3("t1");
        MyThread3 t2 = new MyThread3("t2");
        t1.start();
        t2.start();
    }
}

class MyThread3 extends Thread{
    MyThread3 (String s){
        super(s);
    }

    @Override
    public void run() {
        for (int i = 0;i < 10;i++){
            System.out.println(getName() + ":   " + i);
            if(i % 3 == 0){
                //被2整除则让出CPU,给其他线程执行的机会
                yield();
            }
        }
    }
}

执行结果:
Java多线程机制(一)
可以看出一旦被3整除t1或者t2就会让出线程让对方执行。

五、线程的优先级

  1. Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定调度哪个线程来执行。
  2. 线程优先级用数字表示,范围从1到10,默认是5。
Thread.MIN_PRIORITY = 1;
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
  1. 使用下面的方法获得或设置线程对象的优先级。
int getPriority();
void setPriority(int priority);

示例:

package threadtest;

public class TestPriority {

    public static void main(String[] args) {
        Thread t1 = new Thread(new T1());
        Thread t2 = new Thread(new T2());
        //t1的优先级设置为9
        t1.setPriority(Thread.NORM_PRIORITY + 4);
        t1.start();
        t2.start();
    }

}

class T1 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("T1   " + i);
        }
    }
}

class T2 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("T2  " + i);
        }

    }
}

执行结果:
Java多线程机制(一)
由此可见,线程优先级越高越早执行而且执行的时间片越多,反之,越晚执行。