Java多线程机制(一)
程序员文章站
2022-05-04 19:26:59
...
Java多线程机制
一、线程的基本概念
- 概念: 线程是一个程序内部的顺序控制流
- 线程和进程区别:
(1)每个进程都有独立的代码和数据空间,进程间的切换会有较大的开销。
(2)线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。
(3)多进程:在操作系统中能同时运行多个程序。
(4)多线程:在同一个应用程序中有多个顺序流同时执行。
(5)通俗的说,线程是一个进程里面不同的执行路径,一个进程里面有一个主线程就是main()方法。进程是一个静态的概念,在我们计算机内部实际运行的都是线程。 - Java的线程是通过java.lang.Thread类来实现的。虚拟机启动时会有一个由主方法,也就是main方法所以定义的线程。可以通过创建Thread的实例来创建新的线程。每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。
- 三个原则:
(1)什么是进程?进程是一个静态的概念。
(2)什么事线程?一个进程里面有一个主线程main()方法,是一个程序里面、一个进程里面的不同的执行路径。
(3)在同一个时间点上,一个CPU只能支持一个线程在执行,如果机器是双CPU或者是双核,则支持多线程。
二、线程的创建和启动
两种方式创建和启动新的线程,无论使用哪种方式创建线程,线程的启动都必须调用Thread类的start()方法。原则:只要能使用接口就不用从Thread类继承
- 第一种,定义线程类实现Runnable接口
Thread myThread = new Thread(target) //target为runnable接口类型
//Runnable中只有一个方法:
public void run(); //用于定义线程运行体
使用Runnable接口可以为多个线程提供共享数据。在实现Runnable接口的类的run()方法定义中可以使用Thread的静态方法pulic static Thread currentThread() //获取当前线程的引用
- 第二种,可以定义一个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);
}
}
}
输出结果:
可以看到,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);
}
}
}
可以看到和上面的输出方式是一样的,Main方法和run方法交替运行。
三、线程状态转换
1.当new一个Thread,线程就已经创建了,然后进入就绪状态,当cpu分配给线程时间片,此时该线程进入运行状态,当时间片用完线程又进入就绪状态,然后在分配时间片给线程,如此循环,最终线程终止。
2.线程在运行过程中有可能发生意外导致线程进入阻塞状态,意外接触后,线程进入就绪状态,然后执行过程如上面地说明。
四、线程控制的基本方法
- 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;
}
}
}
}
执行结果:
- 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;
}
}
}
}
执行结果:
- 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();
}
}
}
}
执行结果:
可以看出一旦被3整除t1或者t2就会让出线程让对方执行。
五、线程的优先级
- Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定调度哪个线程来执行。
- 线程优先级用数字表示,范围从1到10,默认是5。
Thread.MIN_PRIORITY = 1;
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
- 使用下面的方法获得或设置线程对象的优先级。
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);
}
}
}
执行结果:
由此可见,线程优先级越高越早执行而且执行的时间片越多,反之,越晚执行。
上一篇: python获取网站图片