Java多线程机制(一)

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);
        }
    }
}

输出结果:
运行结果
可以看到,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.线程在运行过程中有可能发生意外导致线程进入阻塞状态,意外接触后,线程进入就绪状态,然后执行过程如上面地说明。

四、线程控制的基本方法

线程控制的基本方法

  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;
            }
        }
    }
}

执行结果:
输出结果

  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;
            }
        }
    }
}

执行结果:
执行结果

  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();
            }
        }
    }
}

执行结果:
执行结果
可以看出一旦被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多线程机制(二)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值