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


    Java语言内置多线程支持:

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

    1.创建新线程

    要启动一个线程,需创建一个线程对象。创建线程对象的方法有3种。

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

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

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

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

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

    实现Callable接口,覆写call()方法。再用Future进行转换

    class WithResult implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            return 5;
        }
    }
    public class ForZhang {
        public static void main(String[] args) throws Exception{
            Callable<Integer> th = new WithResult();
            FutureTask task = new FutureTask<>(th);
            new Thread(task,"有返回值的线程").start();
        }
    }
    

    示例

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

    class WithResult implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            int i=0;
            for(;i<10;i++){
                System.out.println(Thread.currentThread().getName()+"的循环变量的值"+i);
            }
            return i;
        }
    }
    public class ThirdThread {
        public static void main(String[] args) throws Exception{
            Callable<Integer> th = new WithResult();
            FutureTask task = new FutureTask<>(th);
            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();
            }
        }
    }
    

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

    2.1 直接调用run()方法

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

    class MyThread extends Thread{
        public void run(){
            System.out.println("当前线程"+Thread.currentThread().getName()+"	Hello");
        }
    }
    
    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());
        }
    }
    

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

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

    高优先级的线程将会获得更多的执行机会,因此尽管高优先级的执行晚,却早结束。

    虽然Java提供了10个优先级,但不同操作系统的优先级并不相同,而且也不能很好的和Java的10个优先级对应,因此尽量使用MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY

    4总结:

    • Java用Thread对象表示一个线程,通过调用start()启动一个线程
    • 一个线程对象只能调用一次start()
    • 线程的执行代码是run()方法
    • 线程调度由操作系统决定,程序本身无法决定
    • Thread.sleep()可以把当前线程暂停一段时间
  • 相关阅读:
    POJ1985 树的直径(BFS
    POJ2186 强连通分量+缩点
    AIM Tech Round 5C. Rectangles 思维
    POJ2553 汇点个数(强连通分量
    hdu6370 并查集+dfs
    UVALive 7037:The Problem Needs 3D Arrays(最大密度子图)
    POJ 3155:Hard Life(最大密度子图)
    HDU 5527:Too Rich(DFS+贪心)***
    HDU 5534:Partial Tree(完全背包)***
    Wannafly挑战赛1:Treepath(DFS统计)
  • 原文地址:https://www.cnblogs.com/csj2018/p/10915813.html
Copyright © 2020-2023  润新知