廖雪峰Java11多线程编程-1线程的概念-2创建新线程

本文围绕Java多线程展开,介绍了创建新线程的三种方法,包括使用Thread、Runnable接口、Futrue和Callable。强调启动线程时直接调用run()方法无效,新线程和主线程默认同时执行,由操作系统调度。还阐述了线程优先级的设置与获取,指出程序无法决定线程调度顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java语言内置多线程支持:

  • 一个Java程序实际上是一个JVM进程
  • JVM用一个主线程来执行main()方法
  • 在main()方法中又可以启动多个线程

1.创建新线程

1.1 方法一:使用Thread创建线程

创建MyThread类:

  • 从Thread派生
  • 覆写run()方法
  • 创建MyThread()实例
  • 调用start()启动线程
class MyThread extends Thread{
    public void run(){
        System.out.println("子线程");
    }
}
public class Main {
    public static  void main(String[] args){
        Thread t = new MyThread();
        t.start();
    }
}

1418970-20190609141316985-2073695728.png
疯狂Java示例

package com.thread;

public class FirstThread extends Thread{
    private int i;
    public FirstThread(){}
    public FirstThread(String name){
        super(name);
    }
    public void run(){
        for(;i<10;i++) {
            System.out.println(getName()+i);
        }
    }
    public static void main(String[] args) throws InterruptedException{
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+i);
            if(i==5){
                new FirstThread().start();
                Thread.sleep(500);
                new FirstThread("通过集成Thread创建新线程").start();

            }
            Thread.sleep(500);
        }
    }
}

1418970-20190528195416006-597594251.png

1.2 方法二:使用Runnable接口创建新线程

如果一个类已经从某个类派生,无法从Thread继承:

  • 实现Runnable接口
  • 覆写run()接口
  • 在main()方法中创建Runnable实例
  • 创建Thread实例并传入Runnable
  • 调用start()启动线程
class MyThread implements Runnable{
    public void run(){
        System.out.println("子线程");
    }
}
public class Main {
    public static  void main(String[] args){
        Runnable mt = new MyThread();
        Thread t = new Thread(mt);
        t.start();
    }
}

1418970-20190609142017083-289635030.png

疯狂Java示例

package com.thread;

public class SecondThread implements Runnable{
    private int i;
    public void run(){
        for(;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"的循环变量"+i);
        }
    }
    public static void main(String[] args) throws InterruptedException{
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"的循环变量"+i);
            if(i==5){
                SecondThread st = new SecondThread();
                new Thread(st,"新线程1").start();
                Thread.sleep(500);
                new Thread(st,"新线程2").start();
                Thread.sleep(500);
            }
            Thread.sleep(500);
        }
    }
}

1418970-20190528200822441-445807415.png

1.3 方法三:使用Futrue和Callable创建子线程

package com.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThirdThread{
    public static void main(String[] args) throws InterruptedException{
        ThirdThread th = new ThirdThread();
        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{
            int i=0;
            for(;i<10;i++){
                System.out.println(Thread.currentThread().getName()+"的循环变量的值"+i);
            }
            return i;
        });
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"循环变量的值"+i);
            if(i==5){
                new Thread(task,"有返回值的线程").start();
            }
            Thread.sleep(500);
        }
        try{
            System.out.println("线程task的返回值:"+task.get());
        }catch (ExecutionException e){
            e.printStackTrace();
        }
    }
}

1418970-20190528195605048-2097000123.png

2.启动线程需要注意的地方

2.1 直接调用run()方法

直接调用run()方法是无效的,相当调用普通的Java的方法,当前线程没有任何的改变,也不会启动新的线程。

class MyThread extends Thread{
    public void run(){
        System.out.println("当前线程"+Thread.currentThread().getName()+"\tHello");
    }
}

public class Main {
    public static  void main(String[] args){
        Thread t = new MyThread();
        t.run();//直接调用run()方法
        Thread t2 = new MyThread();
        t2.start();
        System.out.println("主线程"+Thread.currentThread().getName());
    }
}

1418970-20190609144345036-161158297.png

start源码

class Thread implements Runnable {
    public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);

        boolean started = false;
        try {
            start0(); //调用JVM虚拟机内部的start0()方法
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {}
        }
    }

    private native void start0(); //native表示JVM虚拟机内部的C代码实现的,不是由Java代码实现的

2.2 新线程和主线程是同时执行

默认情况下,新线程和主线程是同时执行的,由操作系统调度,程序本身无法确认线程的的调度顺序

class HelloThread extends Thread{
    String name;
    public HelloThread(String name){
        this.name = name;
    }
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("Hello, " + name + "!");
            try{
                Thread.sleep(100);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

public class Main {
    public static  void main(String[] args){
        Thread t1 = new HelloThread("Bob");
        t1.start();
        Thread t2 = new HelloThread("Alice");
        t2.start();
        for(int i=0;i<3;i++){
            System.out.println("Main!");
            try{
                Thread.sleep(100);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

1418970-20190609145950675-1573353895.png

3 线程的优先级

  • 可以对线程设定优先级 Thread.setPriority(int n)//1-10,默认值5
  • getPriority()获取线程的优先级
  • 每个线程默认的优先级都与创建它的父线程的优先级相同,默认情况下,main线程具有普通优先级,其子线程也具有普通优先级。
  • 优先级高的线程被操作系统调度的优先级高
  • 不能通过设置优先级来确保功能的执行顺序
public class PriorityTest extends Thread{
    public PriorityTest(String name){
        super(name);
    }
    public void run(){
        for(int i=0;i<50;i++){
            System.out.println(getName()+",其优先级是:"+getPriority()+"的循环变量的值为:"+i);
        }
    }
    public static void main(String[] args){
        Thread.currentThread().setPriority(6);
        for(int i=0;i<30;i++){
            if(i==10){
                PriorityTest low = new PriorityTest("低级");
                low.start();
                System.out.println("创建之初的优先级:"+low.getPriority());
                low.setPriority(Thread.MIN_PRIORITY);
            }
            if(i==20){
                PriorityTest high = new PriorityTest("高级");
                high.start();
                System.out.println("创建之初的优先级:"+high.getPriority());
                high.setPriority(Thread.MAX_PRIORITY);
            }
        }
    }
}

高优先级的线程将会获得更多的执行机会,因此尽管高优先级的执行晚,却早结束。
1418970-20190609154237642-1111112610.png
虽然Java提供了10个优先级,但不同操作系统的优先级并不相同,而且也不能很好的和Java的10个优先级对应,因此尽量使用MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY

4总结:

  • Java用Thread对象表示一个线程,通过调用start()启动一个线程
  • 一个线程对象只能调用一次start()
  • 线程的执行代码是run()方法
  • 线程调度由操作系统决定,程序本身无法决定
  • Thread.sleep()可以把当前线程暂停一段时间

转载于:https://www.cnblogs.com/csj2018/p/10915813.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值