Java多线程开发--线程常用操作方法

内容学习于:edu.aliyun.com


1. 线程的取名和获得

  多线程的运行状态是不确定的,那么在程序的开发之中为了可以获取到一些需要使用到线程就只能够依靠线程的名字来进行操作。所以线程的名字是-一个至关重要的概念,这样在Thread类之中就提供有线程名称的处理:

  • 构造方法:public Thread(Runnable target , String name);
  • 取得名字: public final String getName()
  • 设置名字:public final void setName(String name)

  对于线程对象的获得是不可能只是依靠一个this来完成的,因为线程的状态不可控,但是有一点是明确的,所有的线程对象一定要执行run()方法,那么这个时候可以考虑获取当前线程,在Thread类里面提供有获取当前线程的方法:

  • 获取当前线程:public static Thread currentThread()

代码:

class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

public class Demo1 {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt, "线程A").start();//设置线程名字
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt, "线程B").start();//设置线程名字
    }
}

结果:

线程A
线程B
Thread-0

  当开发者为线程设置名字的时候就使用设置的名字,而如果没有设置名字,则会自动生成一个不重复的名字,这种自动的属性命名主要是依靠了static属性完成的。

代码:

public class Demo1 {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt).start();//没有设置线程名字
    }
}

结果:

Thread-0
Thread-3
Thread-4
Thread-1
Thread-2

自动命名原理:

  在Thread类里面定义有如下操作:

private static int threadInitNumber;
private static synchronized int nextThreadNum() {
    return threadInitNumber++;
}

代码:

//对象直接调用run()方法
public class Demo1 {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt,"线程对象").start();//设置线程名字
        mt.run();//对象直接调用run()方法
    }
}

观察下面代码:

public class JavaDemo
{
	public static void main(String args[]){
		for(int x= 0; x< Integer.MAX_VALUE;x++){
			System.out.println();
		}
	}
}	

  进程如下图所示:
  <mark>每当启动一个JVM就会启动一个进程,每个主方法都是主进程</mark>
<mark>在任何的开发之中,主线程可以创建若干个子线程,创建子线程的目的是可以将一些复杂逻辑或者比较耗时的逻辑交由子线程处理;</mark>

代码:

例子1:

public class Demo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("1、执行任务一");
        int temp = 0;
        for (int x = 0; x < Integer.MAX_VALUE; x++) {
            temp += x;
        }
        System.out.println("2、执行任务二");
        System.out.println("n、执行任务N");
    }
}

  从结果上看,后续的任务会延迟出现

例子2:

//子线程处理
public class Demo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("1、执行任务一");

        new Thread(() -> {//子线程负责统计
            int temp = 0;
            for (int x = 0; x < Integer.MAX_VALUE; x++) {
                temp += x;
            }
        }).start();

        System.out.println("2、执行任务二");
        System.out.println("n、执行任务N");
    }
}

  <mark>主线程负责处理整体流程,而子线程负责处理耗时操作</mark>,这样将不影响后续的任务进行。

2. 线程的休眠

  如果说现在希望某一个线程可以暂缓执行,那么就可以使用休眠的处理,在Thread类之中定义的休眠方法如下:

  • 休眠:public static void sleep(long millis) throws InterruptedException
  • 休眠:public static void sleep(long millis,int nanos) throws InterruptedException

  在进行休眠的时候有可能会产生中断异常“InterruptedException", 中断异常属于Exception 的子类,所以证明该异常必须进行处理。

线程休眠代码:

public class Demo1 {
    public static void main(String[] args) throws Exception {
        new Thread(() -> { 
            for (int x = 0; x < 10; x++) {
                System.out.println(Thread.currentThread().getName() + "、x=" + x);
                try {
                    Thread.sleep(1000);//暂缓执行
                } catch (InterruptedException e) {//必须处理中断异常
                    e.printStackTrace();
                }
            }
        }).start();

    }
}

  休眠的主要特点是可以自动实现线程的唤醒,以继续进行后续的处理。<mark>但是需要注意的是,如果现在有多个线程对象,那么休眠也是有先后顺序的。</mark>

产生多个多个对象进行休眠处理:

public class Demo1 {
    public static void main(String[] args) throws Exception {
        for (int num = 0; num < 5; num++) {
            new Thread(() -> {
                for (int x = 0; x < 10; x++) {
                    System.out.println(Thread.currentThread().getName() + "、x=" + x);
                    try {
                        Thread.sleep(1000);//暂缓执行
                    } catch (InterruptedException e) {//必须处理中断异常
                        e.printStackTrace();
                    }
                }
            }, "线程" + num).start();
        }
    }
}

  此时将产生五个线程对象,并且这五个线程对象执行的方法体是相同的。此时从程序执行的感觉上来讲好像是若千个线程一起进行了休眠,而后一起进行了自动唤醒,但是实际上是有差别的。
如下图所示:

3. 线程中断

  在之前发现线程的休眠里面提供有一个中断异常,实际上就证明线程的休眠是可以被打断的,而这种打断肯定是由其它线程完成的,在Thread类里面提供有这种中断执行的处理方法:

  • 判断线程是否中断:public static boolean interrupted()
  • 中断线程执行:public void interrupt()

线程中断代码:


public class Demo1 {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(() -> {
            System.out.println("***准备睡觉了***");
            try {
                Thread.sleep(10000);//准备睡10秒
            } catch (InterruptedException e) {
                System.out.println("【敢不让我睡觉???】");
            }
            System.out.println("睡够了!!!");
        });
        thread.start();//开始线程
        Thread.sleep(1000);//先休眠1秒钟
        if (!thread.isInterrupted()) {//判断线程是否中断执行
            System.out.println("【我就轻轻的打扰一下】");
            thread.interrupt();//中断线程
        }
    }
}

结果:

***准备睡觉了***
【我就轻轻的打扰一下】
【敢不让我睡觉???】
睡够了!!!

  所有正在执行的线程都是可以被中断的,<mark>中断线程必须进行异常的处理。</mark>

4. 线程强制执行

  所谓的线程的强制执行指的是当满足于某些条件之后,某一个线程对象将可以一直独占资源,一直到该线程的程序执行结束。

代码:

public class Demo1 {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(() -> {
            for (int x = 0; x < 3; x++) {
                System.out.println(Thread.currentThread().getName() + "执行、x=" + x);
            }
        }, "玩耍的子线程");
        thread.start();//开始线程
        for (int x = 0; x < 3; x++) {
            System.out.println("【霸道的主线程】执行、x=" + x);
        }
    }
}

结果:

【霸道的主线程】执行、x=0
【霸道的主线程】执行、x=1
【霸道的主线程】执行、x=2
玩耍的子线程执行、x=0
玩耍的子线程执行、x=1
玩耍的子线程执行、x=2

  这个时候主线程和子线程都在交替执行着,但是如果说现在你希望主线程独占执行。那么就可以利用Thread类中的方法:

  • 强制执行:public final void join() throws InterruptedException

代码:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int x = 0; x < 5; x++) {
                System.out.println(Thread.currentThread().getName() + "执行、x=" + x);
            }
        }, "玩耍的子线程");
        thread.start();//开始线程
        for (int x = 0; x < 5; x++) {
            if(x==2){
                thread.join();//子线程强行执行
            }
            System.out.println("【霸道的主线程】执行、x=" + x);
        }
    }
}

结果:

【霸道的主线程】执行、x=0
【霸道的主线程】执行、x=1
玩耍的子线程执行、x=0
玩耍的子线程执行、x=1
玩耍的子线程执行、x=2
玩耍的子线程执行、x=3
玩耍的子线程执行、x=4
【霸道的主线程】执行、x=2
【霸道的主线程】执行、x=3
【霸道的主线程】执行、x=4

  <mark>在进行线程强制执行的时候一定要获取强制执行线程对象之后才可以执行join()调用。</mark>

5. 线程礼让

  线程的礼让指的是先将资源让出去让别的线程先执行。线程的礼让可以使用Thread中提供的方法:

  • 礼让:public static void yield()

代码:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread threadA = new Thread(() -> {
            for (int x = 0; x < 10; x++) {
                System.out.println(Thread.currentThread().getName() + "执行、x=" + x);
            }
        }, "玩耍的子线程");
        Thread threadB = new Thread(() -> {
            for (int x = 0; x < 10; x++) {
                if (x % 3 == 0) {
                    System.out.println("【霸道的线程礼让了!!!】");
                    Thread.yield();
                }
                System.out.println(Thread.currentThread().getName() + "执行、x=" + x);
            }
        }, "霸道的子线程");
        threadA.start();//开始线程
        threadB.start();

    }
}

结果:

【霸道的线程礼让了!!!】
玩耍的子线程执行、x=0
霸道的子线程执行、x=0
玩耍的子线程执行、x=1
霸道的子线程执行、x=1
玩耍的子线程执行、x=2
霸道的子线程执行、x=2
【霸道的线程礼让了!!!】
玩耍的子线程执行、x=3
霸道的子线程执行、x=3
玩耍的子线程执行、x=4
霸道的子线程执行、x=4
玩耍的子线程执行、x=5
霸道的子线程执行、x=5
【霸道的线程礼让了!!!】
玩耍的子线程执行、x=6
霸道的子线程执行、x=6
玩耍的子线程执行、x=7
霸道的子线程执行、x=7
玩耍的子线程执行、x=8
霸道的子线程执行、x=8
【霸道的线程礼让了!!!】
玩耍的子线程执行、x=9
霸道的子线程执行、x=9

  <mark>礼让执行的时候每一次调用yield()方法都只会礼让一次当前的资</mark>源。.

6. 线程优先级

  从理论上来讲线程的优先级越高越有可能先执行(越有可能先抢占到资源)。在Thread类里面针对于优先级的操作提供有如下的两个处理方法:

  • 设置优先级:public final void setPriority(int newPriority)
  • 获取优先级:public final int getPriority()

  在进行优先级定义的时候都是通过int型的数字来完成的,而对于此数字的选择在Thread类里面就定义有三个常量:

  • 最高优先级:public static final int MAX_PRIORITY --------10
  • 中等优先级:public static final int NORM_PRIORITY --------5
  • 最低优先级:public static final int MIN_PRIORITY ----------1

代码:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Runnable run = () -> {
            for (int x = 0; x < 3; x++) {
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread threadA = new Thread(run,"线程A");
        Thread threadB = new Thread(run,"线程B");
        Thread threadC = new Thread(run,"线程C");
        
        //设置线程优先级
        threadA.setPriority(Thread.MIN_PRIORITY);
        threadB.setPriority(Thread.MIN_PRIORITY);
        threadC.setPriority(Thread.MAX_PRIORITY);
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

结果:

线程A
线程C
线程B

线程A
线程C
线程B

线程C
线程A
线程B

  <mark>主方法是一个主线程</mark>,那么主线程的优先级呢?

代码:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("主线程优先级:"+Thread.currentThread().getPriority());
        Thread threadA = new Thread(()->{},"线程A");
        System.out.println("子线程优先级:"+threadA.getPriority());
    }
}

结果:

主线程优先级:5
子线程优先级:5

  <mark>主线程是属于中等优先级,而默认创建的线程也是中等优先级。</mark>

全部评论

相关推荐

不愿透露姓名的神秘牛友
07-24 13:40
点赞 评论 收藏
分享
06-27 12:54
已编辑
门头沟学院 Java
累了,讲讲我的大学经历吧,目前在家待业。我是一个二本院校软件工程专业。最开始选专业是觉得计算机感兴趣,所以选择了他。本人学习计算机是从大二暑假结束开始的,也就是大三开始。当时每天学习,我个人认为Java以及是我生活的一部分了,就这样持续学习了一年半,来到了大四上学期末,大概是在12月中旬,我终于找的到了一家上海中厂的实习,但我发现实习生的工作很枯燥,公司分配的活也不多,大多时间也是自己在自学。就这样我秋招末才找到实习。时间来到了3月中旬,公司说我可以转正,但是转正工资只有7000,不过很稳定,不加班,双休,因为要回学校参加答辩了,同时当时也是心高气傲,认为可以找到更好的,所以放弃了转正机会,回学校准备论文。准备论文期间就也没有投递简历。然后时间来到了5月中旬,这时春招基本也结束了,然后我开始投递简历,期间只是约到了几家下场面试。工资也只有6-7k,到现在我不知道该怎么办了。已经没有当初学习的心劲了,好累呀,但是又不知道该干什么去。在家就是打游戏,boss简历投一投。每天日重一次。26秋招都说是针对26届的人,25怎么办。我好绝望。要不要参加考公、考研、央国企这些的。有没有大佬可以帮帮我。为什么感觉别人找工作都是顺其自然的事情,我感觉自己每一步都在艰难追赶。八股文背了又忘背了又忘,我每次都花很长时间去理解他,可是现在感觉八股、项目都忘完了。真的已经没有力气再去学习了。图片是我的简历,有没有大哥可以指正一下,或者说我应该走哪条路,有点不想在找工作了。
码客明:太累了就休息一下兄弟,人生不会完蛋的
如果实习可以转正,你会不...
点赞 评论 收藏
分享
头顶尖尖的程序员:我也是面了三四次才放平心态的。准备好自我介绍,不一定要背熟,可以记事本写下来读。全程控制语速,所有问题都先思考几秒,不要急着答,不要打断面试官说话。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务