zoukankan      html  css  js  c++  java
  • 0039 Java学习笔记-多线程-线程控制、线程组

    join线程

    • 假如A线程要B线程去完成一项任务,在B线程完成返回之前,不进行下一步执行,那么就可以调用B线程的join()方法
    • join()方法的重载:
      • join():等待不限时间
      • join(long millis):等待millis毫秒
      • join(long millis,int nanos):很少用,等待毫秒+毫微秒
    • 看示例:
    package testpack;
    public class Test2  { 
        public static void main(String[] args) throws InterruptedException{ 
        	System.out.println("现在线程是: "+Thread.currentThread().getName());
        	A a=new A();
        	Thread t1=new Thread(a,"被join线程");
        	t1.start();                            //先start,后join
        	t1.join();                             //调用join()方法
        	System.out.println("主线程执行完毕");  //主线程要等t1线程执行完毕,才执行这条语句;如果不调用join(),可能主线程执行完了这条语句,才会执行t1
        }
    }
    class A implements Runnable{
    	public void run(){
    		for (int i=0;i<5;i++){
    			System.out.println(Thread.currentThread().getName()+"  输出: "+i);
    		}
    	}
    }
    

    后台线程

    • 后台线程,又叫守护线程,如果所有的前台线程都执行完毕,那么不论后台线程执行完毕与否,都直接进入死亡状态
    • 前台创建的子线程是前台线程,后台线程创建的子线程是后台线程
    • setDaemon(boolean on):是否将该线程设为后台(true)线程,该方法要在start之前调用,否则抛出IllegalThreadStateException异常
    • isDaemon():判断该线程是不是后台线程
    • 看示例:
    package testpack;
    public class Test2  { 
        public static void main(String[] args) throws InterruptedException{ 
        	Thread t=new Thread(new A(),"后台线程");
    		t.setDaemon(true);    //start之前调用setDaemon方法
    		t.start();
        	for (int i=0;i<10;i++){
        		System.out.println(Thread.currentThread().getName()+" output: "+i);
        	}
        }
    }
    class A implements Runnable{
    	public void run(){
    		for (int i=0;i<50;i++){
    			System.out.println(Thread.currentThread().getName()+"  输出: "+i);
    		}
    	}
    }
    

    输出:

    main output: 0
    main output: 1
    main output: 2
    main output: 3
    main output: 4
    main output: 5
    main output: 6
    后台线程 输出: 0
    main output: 7
    后台线程 输出: 1
    后台线程 输出: 2
    后台线程 输出: 3
    main output: 8
    main output: 9
    后台线程 输出: 4
    后台线程 输出: 5 //后台线程本应执行到49,唯一的前台线程主线程结束后,后台线程也跟着死亡

    线程sleep

    • sleep(long millis):
    • sleet(long millis,int nanos):
    • 该方法让线程暂停执行,交出cpu的执行权,,进入阻塞状态,不释放锁,醒来之后进入就绪状态,不一定能立刻得到执行,看线程调度
    • 示例:
    package testpack;
    
    import java.util.Date;
    
    public class Test2  { 
        public static void main(String[] args) throws InterruptedException{ 
        	System.out.println("当前时间:"+new Date());
        	Thread.sleep(3000);
        	System.out.println("当前时间:"+new Date());
        }
    }
    

    输出:

    当前时间:Thu Dec 08 09:44:02 CST 2016
    当前时间:Thu Dec 08 09:44:05 CST 2016 //主线程暂停执行3秒

    线程yield

    • 线程让步,会使线程从运行状态进入就绪状态,不会进入阻塞状态,这时会让线程优先级相同或更高的线程执行
    • 示例
    package testpack;
    public class Test2  { 
        public static void main(String[] args) throws InterruptedException{ 
        	A a1=new A("线程 低");
        	A a2=new A("线程 中");
        	A a3=new A("线程 高");
        	a1.setPriority(Thread.MIN_PRIORITY);
        	a2.setPriority(Thread.NORM_PRIORITY);
        	a3.setPriority(Thread.MAX_PRIORITY);
        	a1.start();
        	a2.start();
        	a3.start();
        }
    }
    class A extends Thread{
    	A(String name){
    		super(name);
    	}
    	public void run(){
    		for (int i=1;i<10;i++){
    			System.out.println(getName()+" 输出: "+i);
    			if (i==3){
    				Thread.yield();
    			}
    		}
    	}
    }
    

    输出:

    线程 低 输出: 1
    线程 高 输出: 1
    线程 中 输出: 1
    线程 高 输出: 2
    线程 低 输出: 2
    线程 高 输出: 3
    线程 中 输出: 2
    线程 高 输出: 4
    线程 低 输出: 3 //低级线程输出3后,yield,下面让高线程执行
    线程 高 输出: 5
    线程 中 输出: 3 //中级线程输出3后,也yield,下面让高线程执行
    线程 高 输出: 6
    线程 高 输出: 7
    线程 高 输出: 8
    线程 高 输出: 9
    线程 低 输出: 4
    线程 中 输出: 4
    线程 中 输出: 5
    .......

    sleep与yield的对比

    • sleep:运行->阻塞->就绪;yield:运行->就绪
    • sleep之后,其他线程不论优先级高低,都有可能得到执行;yield之后,只有平级或更高级的线程才会被执行
    • sleep声明了抛出InterruptedException异常,yield没有
    • sleep方法移植性更强,不建议用yield来控制并发线程的执行

    线程优先级

    • 线程优先级可以是[1,10]的整数,由setPriority(int newPriority)设置
    • 三个优先级常量:MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY。值分别是10、5、1
    • 每个线程的默认优先级跟创建它的父线程的优先级相同
    • 为了更好的可移植性,建议使用优先级常量,少用int优先级
    • 查看优先级:int getPriority()

    线程组

    • 每个线程都处于一个线程组中,通过线程组,可以对一批线程进行批量控制
    • 如果没有指定线程组,那么处于默认线程组;子线程和创建它的父线程处于同一个线程组
    • 如果要指定一个线程的线程组,应在构造方法中指定,创建了线程实例后,不能改变线程组
    • 如何获得一个线程所属的线程组:getThreadGroup()
    • Thread的构造器中指定线程组
      • Thread(ThreadGroup group,Runnable target):
      • Thread(ThreadGroup group,Runnable target,String name):
      • Thread(ThreadGroup group,String name):
    • ThreadGroup的构造器
      • ThreadGroup(String name):以指定的名称、当前线程所属的线程组创建一个线程组
      • ThreadGroup(ThreadGroup parent, String name):以指定的名称、指定的父线程组创建一个线程组
    • ThreadGroup的几个方法
      • getName():返回该线程组的名字
      • 操作该线程组下的所有线程
        • int activeCount():返回此线程组中活动线程的数目
        • void interrupt():中断该线程组中的所有线程
        • boolean isDaemon():判断是不是后台线程组
        • void setDaemon(boolean daemon):设置为后台线程组,其中的最后一个线程死亡之后,该线程组销毁。特别注意:后台线程组下的线程可不都是后台线程,二者无关
        • void setMaxPriority(int pri):设置该线程组的最高优先级
    System.out.println(Thread.currentThread());
    

    输出:Thread[main,5,main]:第一个main是线程名;5是线程优先级;第二个main是所属线程组名

    • 示例:
    package testpack;
    public class Test2  { 
        public static void main(String[] args) throws InterruptedException{ 
        	System.out.println("主线程名: "+Thread.currentThread().getName()
        			+" ;所属线程组: "+Thread.currentThread().getThreadGroup().getName()
        			+" ;是不是后台线程?"+Thread.currentThread().isDaemon());
        	
        	ThreadGroup tg=new ThreadGroup("后台线程组");
        	tg.setDaemon(true);
        	A a=new A(tg,"后台线程组的线程A");
        	a.start();
        }
    }
    class A extends Thread{
    	A(ThreadGroup group,String name){
    		super(group,name);
    	}
    	public void run(){
    		System.out.println("线程名: "+getName()+" ;所属线程组:"+getThreadGroup().getName()+" ;是不是后台线程?"+isDaemon());
    	}
    }
    

    输出:

    主线程名: main ;所属线程组: main ;是不是后台线程?false
    线程名: 后台线程组的线程A ;所属线程组:后台线程组 ;是不是后台线程?false //后台线程组下的线程不一定是后台线程

    其他

    • 最近发现一个做笔记的地方,蚂蚁笔记:https://leanote.com,支持Markdown,还可以把一篇笔记或一个笔记本公开为博客,可以绑定二级域名或者自定义域名,可以导出为PDF,支持团队协作,甚至是开源的,可以将其部署在自己的服务器上,是一个挺不错的应用
    • 本篇笔记也发布在leanote:在这里
    • 这是我的邀请链接,如果想注册,可以通过该链接,你我都可以获得30天的旗舰版时间
  • 相关阅读:
    ZT 安卓手机的安全性 prepare for Q
    ZT pthread_cleanup_push()/pthread_cleanup_pop()的详解
    <Lord don’t move that mountain>
    C++浅拷贝和深拷贝的区别
    001 Python简介 输入输出
    016 可等待计时器对象.6
    016 EventDemo 5
    016 事件内核对象4
    016 内核对象的Signal状态3
    016 句柄2
  • 原文地址:https://www.cnblogs.com/sonng/p/6145347.html
Copyright © 2011-2022 走看看