java中的线程及常用方法

2.8 线程

2.8.1 线程的概念

程序:保存在物理介质中的代码片段

进程:正在进行当中的程序,就是操作系统的一个进程

线程:一个程序当中一条独立的执行线索

​ 作用:只为让在同一时间做多件事,应对多种需求,服务多个客户,而不是单纯考虑提高效率

​ 实质:宏观并行而围观串行

2.8.2 线程的五大进程(生命周期)

五大状态:
新生(NewBorn) 就绪(Runnable)运行(Running)阻塞(Blocking)消亡(Dead)
在这里插入图片描述
七大状态:
七大状态:新生(NewBorn) 就绪(Runnable)运行(Running)普通阻塞(Blocking)锁池阻塞 等待池阻塞 消亡(Dead)

在这里插入图片描述

2.8.3 实现线程的方式
  1. extends Tread

    class 线程1 extends Thread{
      @Override
      public void run(){
        
      }
    }//直接启动,线程1 x=new 线程1();x.start();
    
    
  2. implements Runnable

    xxxx implements Runnable{
      @Override
      public void run(){
        
      }
    }
    //自己造个Thread对象 传入Runnable对象做参数才能启动
    /*
    线程2 x=new 线程2();
    Thread 对象1=new Thread(x);
    		对象1.start();
    */
    

    注意: 启动线程是调用start() 还是run()
    答:start()
    如果直接调用了run() ,程序当中根本不会多一路线程,而是当前调用run()的那个线程去执行run()当中的代码,等价于 将run()当中的指令,都复制到了当前线程中

2.8.4 控制线程
  1. setPriority(int):设置线程的优先级别,可选范围1-10,默认为5,优先级高代表抢到时间片的概率高

  2. static sleep(long):让当前的线程休眠指定毫秒数

  3. static yield();让当前线程直接放弃时间片返回就绪【很可能自投自抢的情况,比较浪费CPU资源,建议少用】

  4. join():让当前线程邀请调用方法的那个线程优先执行,在被邀请的线程执行结束之前当前线程一直处于阻塞状态,不再继续执行

*:线程类所有静态方法,不要关注谁调用了,而要关注调用的位置,出现在哪个线程体,该线程就执行该方法。

*:线程类所有涉及主动进入阻塞状态的方法(sleep() / join() / await() / wait())都必须进行异常处理,因为他们都有throws InterruptedException,这个是非运行时异常,必须处理。

*: 阻塞状态的线程 如何解除阻塞?
sleep() : 睡眠的时间超时了 就自动解除
join() : 被邀请的线程执行结束了 就自动解除
await() : 门闩都被拔掉的时候 就解除阻塞
wait() : 被其它线程notify()/notifyAll() 就解除阻塞
*: interrupt() 能够在这些条件都没满足的情况下 直接揍醒

进度条sleep

for(int i = 0;i<=100;i++){
			System.out.print("\r已经完成"+i+"%");
			Thread.sleep(100);

睡眠排序(升序)

public class TestSortedSleep{
public static void main(String[] args){
   int[] data=new int[]{23,65,32,1,4,67,88,9,46};
   for(int x:data){
	   Sleep sleep=new Sleep(x);
	   sleep.start();
	   }
}
}
class Sleep extends Thread{
	int num;
	public   Sleep(int num){
		this.num=num;
	}
	@Override
	public void run(){
		try{
			Thread.sleep(num);
			}catch(Exception e){
				e.printStackTrace();
			}
        System.out.println(num);
		}
	}

yield打印1-26和a-z

class NumThread extends Thread{
	@Override
	public void run(){
		for(int i = 1;i<=26;i++){
			System.out.println(i);
			Thread.yield();
		}
	}
}
class CharThread extends Thread{
	@Override
	public void run(){
		for(char c = 'a';c<='z';c++){
			System.out.println(c);
			Thread.yield();
		}
	}
}

join实例

public class TestJoin{
	public static void main(String[] args)throws Exception{
		EtoakThread et = new EtoakThread();
		et.start();
		/*
			当前线程(主线程)   邀请   调用方法的线程(et)

			优先执行 在et执行结束之前 主线程一直阻塞 不再继续执行

		*/
		et.join();

		for(int i = 0;i<6666;i++){
			System.out.println("梦回吹角连营");
		}
	}
}
class EtoakThread extends Thread{
	@Override
	public void run(){
		for(int i = 0;i<6666;i++){
			System.out.println("醉里挑灯看剑");
		}
	}
}
2.8.5 线程类其他常用方法:

setName():设置线程的名字

getName():得到线程的名字

static activeCount():得到程序中所有活跃的线程:就绪+运行+阻塞

setDaemon(true):设置线程成为守护线程(为了给别的线程提供服务的)

​ 当程序当中只剩下守护线程的时候,守护线程会自行消亡(收尾工作 )

注意:

  • 守护线程需要无限循环,防止其过早消亡
  • 设置成为守护线程必须早于自己的start()
  • 守护线程应该具有较低的优先级

interrupt():中断,打断线程中的阻塞状态

*:sleep()和join()都能导致线程阻塞

static currentThread():得到当前正在运行状态的线程对象

  1. 在主线程(main方法)当中,用于获得主线程对象,java当中唯一可以获得主线程对象的方式
  2. 在run()调用的其他方法中,用于获得当前线程

注意事项不应该出现在run方法体中,因为得到的线程就是this

static activeCount案例

public class TestActiveCount{
	public static void main(String[] args){
		int x = (int)(Math.random()*3)+3;//3-5
		for(int i = 0;i<x;i++){
			EtoakThread et = new EtoakThread();
			et.start();
		}
			System.out.println(Thread.activeCount());//包含主线程main
	}
}
class EtoakThread extends Thread{
	@Override
	public void run(){
		for(int i = 0;i<100;i++){
			System.out.println("碾碎他们~");
		}
	}
}

setDaemon(true)案例

public class TestSetDaemon{
	public static void main(String[] args){
		GYJJ gy = new GYJJ();
		gy.setDaemon(true);//必须早于自身的start();
		gy.start();
		gy.setPriority(1);//守护线程应当具有最低的优先级
		for(int i = 0;i<100;i++){
			System.out.println("西天取经上大路 一走就是几万里");
		}

	}
}
class GYJJ extends Thread{
	@Override
	public void run(){
		//守护线程通常都是无限循环 以防止其过早消亡
		while(true){
			System.out.println("你这泼猴儿");
		}
	}
}

interrupt()案例

public class TestInterrupt{
	public static void main(String[] args)throws Exception{
		EtoakThread et = new EtoakThread();
		et.start();
		/*
			主动出手打人的(主线程)  被动挨打的(et线程)
		*/
		et.interrupt();
	}
}
class EtoakThread extends Thread{
	@Override
	public void run(){
		try{
			Thread.sleep(9999999999999999L);
		}catch(Exception e){
			e.printStackTrace();
		}
		System.out.println("吖!神清气爽吖!");
	}
}

static currentThread()案例

//放在主线程(main方法里面)用来获得主线程对象
public static void main(String[] args){
//让主线程的优先级 从默认的5 变成10
		Thread zxc = Thread.currentThread();
		zxc.setPriority(10);}
//放在run()调用的方法里面,用来获得当前线程对象
public class TestCase{
public static void main(String[] args){
  Student stu=new Student("张三");
  stu.start();

}}
class Student extends Thread{
  public Student(String name){
    setName(name);
  }
  @Override
  public void run(){
    System.out.println(getName()+"同学要问老师问题");
    Teacher t1=new Teacher();
    t1.answer();

  }
}

class Teacher {
public void answer(){
		Thread t = Thread.currentThread();
		String name = t.getName();
		System.out.println("老师认真回答"+name+"同学的问题");}}

CountDownLatch->替代连环try

方法:await():

​ countDown():

CountDown方法实战案例

import java.util.*;
import java.util.concurrent.*;
public class TestCurrentThread{
	public static void main(String[] args) throws Exception{
		Student stu1=new Student("小明");
		Student stu2=new Student("小红");
		Student stu3=new Student("小强");
		stu1.start();
		stu2.start();
		stu3.start();
		try{
			X.cd.await();//学生线程结束,插上插销,进入等待
			}catch(Exception e){
				e.printStackTrace();
				}
           System.out.println("========账本=========");
           Teacher tea=Teacher.getTea();
           Map<Integer,String> temp=new TreeMap<>((a,b)->a.equals(b)?1:b.compareTo(a));
           tea.map.forEach((name,count)->temp.put(count,name));
           temp.forEach((count,name) -> System.out.println(name + " : " + count));//按照value降序排序
          /* Set<Map.Entry<String,Integer>> es=tea.map.entrySet();
           for(Map.Entry<String,Integer> jilu:es){
			   String name=jilu.getKey();
			   Integer count=jilu.getValue();
			   System.out.println(name+":"+count);
			   }*/

	}
}
class X  {
	static CountDownLatch cd = new CountDownLatch(3);

	}
class Student extends Thread{
	public Student(String name){
		setName(name);
		}
	@Override
	public void  run(){
		System.out.println(getName()+"同学学习过程中遇到问题,想问老师");
	   Teacher tea=Teacher.getTea();
		int x=(int)(Math.random()*10)+1;
		for(int i=0;i<x;i++){
				tea.answer();
			}
			X.cd.countDown();//访问完毕,拔掉插销,撤销等待

		}

	}
	class Teacher extends Thread{
		Map<String,Integer> map=new ConcurrentHashMap<>();
		private Teacher(){}
		private static Teacher tea=new Teacher();
		public static Teacher getTea(){
			return tea;}

		public void answer(){
			Thread t=Thread.currentThread();//获得调用该方法的线程对象
			String name=t.getName();
			System.out.println("认真解答"+name+"的问题");
			if(map.containsKey(name)){
				map.put(name,map.get(name)+1);
				}else{
					map.put(name,1);
					}
			}

		}

利用可变参实现线程相继启动

public class Exec{
public static void main(String[] args){
	//自定向下new对象,num的值也呈现5、4、3、2、1的变化
	Print p5=new Print();//num=5,无线程要紧随其后启动
	Print p4=new Print();//num=4,无线程要紧随其后启动
	Print p3=new Print(p4,p5);//num=3,执行完成后需要启动p4和p5两个线程对象
	Print p2=new Print(p3);//num=2,执行完成后需要启动p3线程对象
	Print p1=new Print(p2);//num=1,执行完成后需要启动p2线程对象
	p1.start();//只需要启动p1,就能启动所有连续需要启动的进程,
}
}

class Print extends Thread{
	int num;
	static int id;
	Thread[] ts;
	public Print(Thread ... ts ){//可变参实现不定数量传参
		this.num=5-(id++);//num的值为5、4、3、2、1
		this.ts=ts;
		}

	@Override
	public void run(){
		  for(int i=0;i<100;i++){
		  			System.out.println("我是线程"+num+"号");
			}
			if(ts!=null){//需要判断ts集合中是否有进程,有则让他启动
				for(Thread t:ts){
					t.start();
					}
				}
		}
	}

CountDownLatch用法详解参考链接
感谢您的浏览与点赞,让我们一起快乐学java!
在这里插入图片描述

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值