JAVA多线程知识总结(二)

本文是承接上一篇文章:JAVA多线程知识总结(一)

四.Java多线程的阻塞状态与线程控制 

    上文已经提到线程阻塞的集中具体类型。下面主要看引起JAVA线程阻塞的方法

  1,join()-----让一个线程等待另一个线程完成之后才继续执行,如A线程的执行体中调用B线程的join方法,则A线程被阻塞,知道B线程执行完成之后,A才得以继续执行

package com.bpan.spring.beans.thread;

public class ThreadTestJoin {

    public static void main(String[] args) {

        MyRunnable2 myRunnable2 = new MyRunnable2();

        Thread thread = new Thread(myRunnable2);

        for( int i = 0; i < 30 ; i++) {

            System.out.println(Thread.currentThread().getName()+" "+i);

            if (i==10) {

                thread.start();

                try {
                    thread.join(); //main线程需要等待thread线程执行完毕之后再执行
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

        }
    }

}

class MyRunnable2 implements Runnable{

    @Override
    public void run() {

        for(int i = 0; i< 20;i++) {

            System.out.println(Thread.currentThread().getName()+" "+i);
        }

    }
}

为了查看明显的join()方法的作用,你可以将调用join()方法的代码注释掉,然后比较前后的运行结果,很明显地能够看到join()方法的作用。

  2,sleep()

  sleep —— 让当前的正在执行的线程暂停指定的时间,并进入阻塞状态。在其睡眠的时间段内,该线程由于不是处于就绪状态,因此不会得到执行的机会。即使此时系统中没有任何其他可执行的线程,出于sleep()中的线程也不会执行。因此sleep()方法常用来暂停线程执行。

前面有讲到,当调用了新建的线程的start()方法后,线程进入到就绪状态,可能会在接下来的某个时间获取CPU时间片得以执行,如果希望这个新线程必然性的立即执行,直接调用Thread静态方法的sleep(1)即可。

package com.bpan.spring.beans.thread;

public class ThreadTestJoin {

    public static void main(String[] args) {

        MyRunnable2 myRunnable2 = new MyRunnable2();

        Thread thread = new Thread(myRunnable2);

        for( int i = 0; i < 30 ; i++) {

            System.out.println(Thread.currentThread().getName()+" "+i);

            /*try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }*/

            if (i==10) {

                thread.start();

                try {
//                    thread.join(); //main线程需要等待thread线程执行完毕之后再执行

                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

        }
    }

}

class MyRunnable2 implements Runnable{

    @Override
    public void run() {

        for(int i = 0; i< 20;i++) {

            /*
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }*/
            System.out.println(Thread.currentThread().getName()+" "+i);
        }

    }
}

注:睡一个毫秒级够了,因为CPU不会空闲,会切换到新建的线程。

  3,后台线程

概念/目的:后台线程主要是为其他线程(相对可以称之为前台线程)提供服务,或“守护线程”。如JVM中的垃圾回收线程。

生命周期:后台线程的生命周期与前台线程生命周期有一定关联。主要体现在:当所有的前台线程都进入死亡状态时,后台线程会自动死亡(其实这个也很好理解,因为后台线程存在的目的在于为前台线程服务的,既然所有的前台线程都死亡了,那它自己还留着有什么用...伟大啊 ! !)。

设置后台线程:调用Thread对象的setDaemon(true)方法可以将指定的线程设置为后台线程。

package com.bpan.spring.beans.thread;

public class DeamonThread {

    public static void main(String[] args) {
        Thread myThread = new MyThread2();
        for (int i = 0; i < 100; i++) {
            System.out.println("main thread i = " + i);
            if (i == 20) {
                myThread.setDaemon(true);
                myThread.start();
            }
        }
    }

}

class MyThread2 extends Thread{

    @Override
    public void run() {

        for (int i = 0; i < 100; i++) {
            System.out.println("i = " + i);
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

判断线程是否是后台线程:调用thread对象的isDeamon()方法。

注:main线程默认是前台线程,前台线程创建中创建的子线程默认是前台线程,后台线程中创建的线程默认是后台线程。调用setDeamon(true)方法将前台线程设置为后台线程时,需要在start()方法调用之前。前天线程都死亡后,JVM通知后台线程死亡,但从接收指令到作出响应,需要一定的时间。

4.改变线程的优先级/setPriority():

  每个线程在执行时都是具有一定的优先级的,优先级高的线程具有较多的执行机会。每个线程的优先级都与创建它的线程的优先级相同,main线程默认具有普通优先级。

  设置线程的优先级:setPriority(int priorityLevel)   

参数priorityLevel范围在1-10之间,常用的有如下三个静态常量值:

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

获取线程优先级:getPriority()。

注:具有较高线程优先级的线程对象仅表示此线程具有较多的执行机会,而非优先执行。

package com.bpan.spring.beans.thread;

public class ThreadTest {

    public static void main(String[] args) {

        Thread thread = new MyThread5();

        for(int i = 0; i<100; i++) {

            System.out.println("main thread i= " + i);

            if (i == 20) {

                thread.setPriority(Thread.MAX_PRIORITY);
                thread.start();
            }
        }

    }
}

class MyThread5 extends Thread{

    @Override
    public void run() {

        for (int i = 0; i < 100; i++) {
            System.out.println("i = " + i);
        }

    }

}

5.线程让步:yield()

  yield()方法的作用就是是当前线程释放占用的CPU资源,由运行状态转换为就绪状态,但是CPU调度具有随机性,下次运行的线程有可能还是调用yield()方法的线程。

  需要注意的另一点就是:yield()方法从运行状态转换到就绪状态后,CPU从就绪状态线程列表中只会选择与该线程优先级同级别或者优先级更高的线程去执行。

package com.bpan.spring.beans.thread;

public class ThreadTestMain {

    public static void main(String[] args) {
        Thread myThread1 = new MyThread3();
        Thread myThread2 = new MyThread4();
        myThread1.setPriority(Thread.MAX_PRIORITY);
        myThread2.setPriority(Thread.MIN_PRIORITY);
        for (int i = 0; i < 100; i++) {
            System.out.println("main thread i = " + i);
            if (i == 20) {
                myThread1.start();
                myThread2.start();
                Thread.yield();
            }
        }
    }

}

class MyThread3 extends Thread {

    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("myThread 1 --  i = " + i);
        }
    }
}

class MyThread4 extends Thread {

    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("myThread 2 --  i = " + i);
        }
    }
}

原文地址:https://www.cnblogs.com/revel171226/p/9418099.html

时间: 2024-08-01 14:54:35

JAVA多线程知识总结(二)的相关文章

Java多线程知识小抄集(二)

本文主要整理博主遇到的Java多线程的相关知识点,适合速记,故命名为"小抄集".本文没有特别重点,每一项针对一个多线程知识做一个概要性总结,也有一些会带一点例子,习题方便理解和记忆. 1-26请参考<Java多线程知识小抄集(一)> 27. ConcurrentHashMap ConcurrentHashMap是线程安全的HashMap,内部采用分段锁来实现,默认初始容量为16,装载因子为0.75f,分段16,每个段的HashEntry 28. 线程安全的非阻塞队列 非阻塞

Java多线程知识小抄集(三)

本文主要整理博主遇到的Java多线程的相关知识点,适合速记,故命名为"小抄集".本文没有特别重点,每一项针对一个多线程知识做一个概要性总结,也有一些会带一点例子,习题方便理解和记忆. 51. SimpleDateFormat非线程安全 当多个线程共享一个SimpleDateFormat实例的时候,就会出现难以预料的异常. 主要原因是parse()方法使用calendar来生成返回的Date实例,而每次parse之前,都会把calendar里的相关属性清除掉.问题是这个calendar是

java基础知识(二)

1.关于static关键字总结: 1.不能在static修饰的方法中引用this变量,只能引用一些静态变量或方法,或new新的对象(可以定义局部变量). 简言之,静态方法或块中,只能引用静态的方法或变量. 2.类中的成员变量(static修饰)有缺省值,而类的定义的方法中的局部变量没有缺省值. 3.在类的构造器中,可以引用任何的静态或非静态的变量和方法,可以在非static方法中调用static方法. 4.static{}块中的代码在类装载中仅执行一次. 5.在7-7,A staticmetho

Java多线程基础(二)定时器类:Timer类和TimerTask类

Java多线程基础(二)定时器类:Timer类和TimerTask类 Timer类和TimerTask类是jdk实现定时器功能的早期方法,jdk1.5以前就支持Timer类和TimerTask类.JDK1.5之后引入了新的机制,将在后续博文中研究. 1 指定时间间隔后执行任务 import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class TraditionalTimerTest {

Java多线程知识小抄集(一)

本文主要整理博主遇到的Java多线程的相关知识点,适合速记,故命名为"小抄集".本文没有特别重点,每一项针对一个多线程知识做一个概要性总结,也有一些会带一点例子,习题方便理解和记忆. 1. interrupted与isInterrupted的区别 interrupted():测试当前线程是否已经是中断状态,执行后具有状态标志清除为false的功能. isInterrupted():测试线程Thread对象是否已经是中断状态,但不清楚状态标志. 方法: public static boo

java多线程知识总结(四)

同步器的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态,在抽象方法的实现过程中免不了要对同步状态来进行修改,也就是int成员变量,这时就需要使用同步器提供的3个方法来进行性操作,这三个方法包括:getState().setState().compareAndSetState(),因为它们能够保证状态的改变是安全地. 示例一:三个售票窗口同时出售20张票; 程序分析:1.票数要使用同一个静态值 2.为保证不会出现卖出同一个票数,要java多线程同步锁. 设计思路:1.创建一

Java多线程详解(二)

评论区留下邮箱可获得<Java多线程设计模式详解> 转载请指明来源 1)后台线程 后台线程是为其他线程服务的一种线程,像JVM的垃圾回收线程就是一种后台线程.后台线程总是等到非后台线程死亡之后,后台线程没有了服务对象,不久就会自动死亡,不再复活.利用setDaemon方法可以把一个线程设置为后台线程,但必须在线程启动之前调用. 例如 : /* * @author [email protected] */ public class DaemonThread extends Thread { pu

java多线程笔记(二)

      java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Semaphore.   线程同步问题引入:       创建一个银行账户Account类,在创建并启动100个线程往同一个Account类实例里面添加一块钱.在没有使用上面三种方法的情况下: 代码: import java.util.concurrent.ExecutorService; import

Java多线程编程(二)

在 Java多线程编程(一) 中的多线程并没有返回值,本文将介绍带返回值的多线程. 要想有返回值,则需要实现新的接口Callable而不再是Runnable接口,实现的方法也改为call()方法,执行器也不再是调用execute(),而是submit() [程序实例] 1 public class TaskWithResult implements Callable<String> { 2 3 private int id; 4 5 public TaskWithResult(int id)