how2j.cn

本视频是解读性视频,所以希望您已经看过了本知识点的内容,并且编写了相应的代码之后,带着疑问来观看,这样收获才多。 不建议一开始就观看视频



16分9秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)



关键字 简介 示例代码
sleep
当前线程暂停
示例代码
join
加入到当前线程中
示例代码
setPriority
线程优先级
示例代码
yield
临时暂停
示例代码
setDaemon
守护线程
示例代码
练习-英雄充能
示例代码
答案-英雄充能
示例代码
练习-破解密码
示例代码
答案-破解密码
示例代码
示例 1 : 当前线程暂停   
示例 2 : 加入到当前线程中   
示例 3 : 线程优先级   
示例 4 : 临时暂停   
示例 5 : 守护线程   
示例 6 : 练习-英雄充能   
示例 7 : 答案-英雄充能   
示例 8 : 练习-破解密码   
示例 9 : 答案-破解密码   

示例 1 :

当前线程暂停

edit
Thread.sleep(1000); 表示当前线程暂停1000毫秒 ,其他线程不受影响
Thread.sleep(1000); 会抛出InterruptedException 中断异常,因为当前线程sleep的时候,有可能被停止,这时就会抛出 InterruptedException
package multiplethread; public class TestThread { public static void main(String[] args) { Thread t1= new Thread(){ public void run(){ int seconds =0; while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.printf("已经玩了LOL %d 秒%n", seconds++); } } }; t1.start(); } }
示例 2 :

加入到当前线程中

edit
首先解释一下主线程的概念
所有进程,至少会有一个线程即主线程,即main方法开始执行,就会有一个看不见的主线程存在。
在42行执行t.join,即表明在主线程中加入该线程
主线程会等待该线程结束完毕, 才会往下运行。
package multiplethread; import charactor.Hero; public class TestThread { public static void main(String[] args) { final Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 616; gareen.damage = 50; final Hero teemo = new Hero(); teemo.name = "提莫"; teemo.hp = 300; teemo.damage = 30; final Hero bh = new Hero(); bh.name = "赏金猎人"; bh.hp = 500; bh.damage = 65; final Hero leesin = new Hero(); leesin.name = "盲僧"; leesin.hp = 455; leesin.damage = 80; Thread t1= new Thread(){ public void run(){ while(!teemo.isDead()){ gareen.attackHero(teemo); } } }; t1.start(); //代码执行到这里,一直是main线程在运行 try { //t1线程加入到main线程中来,只有t1线程运行结束,才会继续往下走 t1.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } Thread t2= new Thread(){ public void run(){ while(!leesin.isDead()){ bh.attackHero(leesin); } } }; //会观察到盖伦把提莫杀掉后,才运行t2线程 t2.start(); } }
当线程处于竞争关系的时候,优先级高的线程会有更大的几率获得CPU资源
为了演示该效果,要把暂停时间去掉,多条线程各自会尽力去占有CPU资源
同时把英雄的血量增加100倍,攻击减低到1,才有足够的时间观察到优先级的演示
如图可见,线程1的优先级是MAX_PRIORITY,所以它争取到了更多的CPU资源执行代码
线程优先级
package charactor; import java.io.Serializable; public class Hero{ public String name; public float hp; public int damage; public void attackHero(Hero h) { //把暂停时间去掉,多条线程各自会尽力去占有CPU资源 //线程的优先级效果才可以看得出来 // try { // // Thread.sleep(0); // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } h.hp-=damage; System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n",name,h.name,h.name,h.hp); if(h.isDead()) System.out.println(h.name +"死了!"); } public boolean isDead() { return 0>=hp?true:false; } }
package multiplethread; import charactor.Hero; public class TestThread { public static void main(String[] args) { final Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 6160; gareen.damage = 1; final Hero teemo = new Hero(); teemo.name = "提莫"; teemo.hp = 3000; teemo.damage = 1; final Hero bh = new Hero(); bh.name = "赏金猎人"; bh.hp = 5000; bh.damage = 1; final Hero leesin = new Hero(); leesin.name = "盲僧"; leesin.hp = 4505; leesin.damage = 1; Thread t1= new Thread(){ public void run(){ while(!teemo.isDead()){ gareen.attackHero(teemo); } } }; Thread t2= new Thread(){ public void run(){ while(!leesin.isDead()){ bh.attackHero(leesin); } } }; t1.setPriority(Thread.MAX_PRIORITY); t2.setPriority(Thread.MIN_PRIORITY); t1.start(); t2.start(); } }
当前线程,临时暂停,使得其他线程可以有更多的机会占用CPU资源
package multiplethread; import charactor.Hero; public class TestThread { public static void main(String[] args) { final Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 61600; gareen.damage = 1; final Hero teemo = new Hero(); teemo.name = "提莫"; teemo.hp = 30000; teemo.damage = 1; final Hero bh = new Hero(); bh.name = "赏金猎人"; bh.hp = 50000; bh.damage = 1; final Hero leesin = new Hero(); leesin.name = "盲僧"; leesin.hp = 45050; leesin.damage = 1; Thread t1= new Thread(){ public void run(){ while(!teemo.isDead()){ gareen.attackHero(teemo); } } }; Thread t2= new Thread(){ public void run(){ while(!leesin.isDead()){ //临时暂停,使得t1可以占用CPU资源 Thread.yield(); bh.attackHero(leesin); } } }; t1.setPriority(5); t2.setPriority(5); t1.start(); t2.start(); } }
守护线程的概念是: 当一个进程里,所有的线程都是守护线程的时候,结束当前进程。

就好像一个公司有销售部,生产部这些和业务挂钩的部门。
除此之外,还有后勤,行政等这些支持部门。

如果一家公司销售部,生产部都解散了,那么只剩下后勤和行政,那么这家公司也可以解散了。

守护线程就相当于那些支持部门,如果一个进程只剩下守护线程,那么进程就会自动结束。

守护线程通常会被用来做日志,性能统计等工作。
package multiplethread; public class TestThread { public static void main(String[] args) { Thread t1= new Thread(){ public void run(){ int seconds =0; while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.printf("已经玩了LOL %d 秒%n", seconds++); } } }; t1.setDaemon(true); t1.start(); } }
示例 6 :

练习-英雄充能

edit Or  姿势不对,事倍功半! 点击查看做练习的正确姿势
英雄有可以放一个技能叫做: 波动拳-a du gen。
每隔一秒钟,可以发一次,但是只能连续发3次。

发完3次之后,需要充能5秒钟,充满,再继续发。

借助本章节学习到的知识点,实现这个效果
练习-英雄充能
示例 7 :

答案-英雄充能

edit
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看本答案会花费3个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
查看本答案会花费3个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
账号未激活 账号未激活,功能受限。 请点击激活
package charactor; public class Hero { public String name; public float hp; public Hero() { } public Hero(String name) { this.name = name; } public int damage; public void attackHero(Hero h) { try { // 为了表示攻击需要时间,每次攻击暂停1000毫秒 Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } h.hp -= damage; System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n", name, h.name, h.name, h.hp); if (h.isDead()) System.out.println(h.name + "死了!"); } public boolean isDead() { return 0 >= hp ? true : false; } int totalTime = 3; public void adugen() { while (true) { for (int i = 0; i < totalTime; i++) { System.out.printf("波动拳第%d发%n", i + 1); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("开始为时5秒的充能"); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { Hero h = new Hero(); h.name = "红仔"; h.adugen(); } }
示例 8 :

练习-破解密码

edit Or  姿势不对,事倍功半! 点击查看做练习的正确姿势
1. 生成一个长度是3的随机字符串,把这个字符串当作 密码

2. 创建一个破解线程,使用穷举法,匹配这个密码

3. 创建一个日志线程,打印都用过哪些字符串去匹配,这个日志线程设计为守护线程

提示: 破解线程把穷举法生成的可能密码放在一个容器中,日志线程不断的从这个容器中拿出可能密码,并打印出来。 如果发现容器是空的,就休息1秒,如果发现不是空的,就不停的取出,并打印。

参考: 穷举法破解密码
示例 9 :

答案-破解密码

edit
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看本答案会花费5个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
查看本答案会花费5个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
账号未激活 账号未激活,功能受限。 请点击激活
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频

10分16秒 本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)


package multiplethread; import java.util.List; public class PasswordThread extends Thread{ private boolean found = false; private String password; private List<String> passwords; public PasswordThread(String password, List<String> passwords) { this.password = password; this.passwords = passwords; } public void run(){ char[] guessPassword = new char[password.length()]; generatePassword(guessPassword, password); } public void generatePassword(char[] guessPassword, String password) { generatePassword(guessPassword, 0, password); } public void generatePassword(char[] guessPassword, int index, String password) { if (found) return; for (short i = '0'; i <= 'z'; i++) { char c = (char) i; if (!Character.isLetterOrDigit(c)) continue; guessPassword[index] = c; if (index != guessPassword.length - 1) { generatePassword(guessPassword, index + 1, password); } else { String guess = new String(guessPassword); //穷举每次生成的密码,都放进集合中 passwords.add(guess); if (guess.equals(password)) { System.out.println("找到了,密码是" + guess); found = true; return; } } } } }
package multiplethread; import java.util.List; public class LogThread extends Thread{ private boolean found = false; private List<String> passwords; public LogThread(List<String> passwords) { this.passwords = passwords; this.setDaemon(true);//把记日志的这个线程,设置为守护线程 } public void run(){ while(true){ while(passwords.isEmpty()){ try { Thread.sleep(50); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } String password = passwords.remove(0); System.out.println("穷举法本次生成的密码是:" +password); } } }
package multiplethread; import java.util.ArrayList; import java.util.List; public class TestThread { public static boolean found = false; public static void main(String[] args) { String password = randomString(3); System.out.println("密码是:" + password); List<String> passwords = new ArrayList<>(); new PasswordThread(password,passwords).start(); new LogThread(passwords).start(); } private static String randomString(int length) { String pool = ""; for (short i = '0'; i <= '9'; i++) { pool += (char) i; } for (short i = 'a'; i <= 'z'; i++) { pool += (char) i; } for (short i = 'A'; i <= 'Z'; i++) { pool += (char) i; } char cs[] = new char[length]; for (int i = 0; i < cs.length; i++) { int index = (int) (Math.random() * pool.length()); cs[i] = pool.charAt(index); } String result = new String(cs); return result; } }


HOW2J公众号,关注后实时获知布最新的教程和优惠活动,谢谢。


问答区域    
2019-05-16 练习:匿名类破解密码求指教
yutou



找到密码后,破解线程结束了。但守护线程还要继续打印一段数据才结束,是否正常?
public class TestThread {
	//创建长度为length的随机字符串
public static String RandomString(int length) {
	String  pool="";
	for(char i ='0';i<'9';i++) {
		pool +=i;
	}
	for(char j ='a';j<'z';j++) {
		pool +=j;
	}
	for(char k='A';k<'Z';k++) {
		pool +=k;
	}
	char [] s=new char[length];
	for(int i =0;i<s.length;i++) {
		s[i] =pool.charAt((int) (Math.random()*pool.length()));
	}
	return new String(s);
}
//判断所给的三个字符是不是数字或者字母
private static boolean IsDigitOrLetter(char i, char j, char k) {
	
	return Character.isLetterOrDigit(i)&&
			Character.isLetterOrDigit(j)&&
			Character.isLetterOrDigit(k);
}
	public static void main(String[] args) {
     String password =RandomString(3);
     System.out.println("随机密码是:"+password);
     ArrayList<String> list = new ArrayList<>();//存放可能的密码
     //线程1:穷举法找密码
     Thread t1= new Thread() {
    	 public void run() {
    		char [] guesspsw=new char[3];
    		for(char i ='0';i<'z';i++) 
    		for(char j ='0';j<'z';j++) 
    		for(char k='0';k<'z';k++) {
    			if(!IsDigitOrLetter(i,j,k)) continue;
    			guesspsw[0]=i;
    			guesspsw[1]=j;
    			guesspsw[2]=k;
    			String str =new String(guesspsw);//穷举法每次得到的可能密码
    			list.add(str);
    			//System.out.println("已经将可能的密码放入了list中");
    			if (str.equals(password)) {
    				System.out.println("找到了,密码是"+str);
    				break;
    			}
    			
    		}
     }

		
     } ;
     t1.start();
     //线程2:打印可能的密码
     Thread t2=new Thread() {
    	 public void run() {
    		 if(null==list) {
    			 try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
    		 }
    	else {
    		  for(int i =0;i<list.size();i++) {
    			  System.out.println("可能的密码是:"+list.get(i)); 
    			  list.remove(list.get(i));
    			 }
    	}
    		 }
     };
     t2.setDaemon(true);
     t2.start();
     
}
}

							





回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2019-05-16 练习:英雄充能
yutou



波动拳第1发 波动拳第2发 波动拳第3发 开始为时5秒的充能 波动拳第1发 波动拳第2发 波动拳第3发 开始为时5秒的充能 波动拳第1发 波动拳第2发 波动拳第3发 开始为时5秒的充能 波动拳第1发 波动拳第2发 波动拳第3发 开始为时5秒的充能 波动拳第1发 波动拳第2发 波动拳第3发 开始为时5秒的充能
public class Hero implements Comparable<Hero>{
	//表示这个类当前的版本,如果有了变化,比如新设计了属性,就应该修改这个版本号
    private static final long serialVersionUID = 1L;
    public String name;
    public float hp;
    public int damage;     
    public Hero(String name) {
    	this.name=name;
    	
    }
    public String toString() {
        return "Hero [name=" + name + ", hp=" + hp + ", damage=" + damage + "]\r\n";
    }
 
    public Hero(String name, int hp, int damage) {
        this.name = name;
        this.hp = hp;
        this.damage = damage;
    }
    public Hero() {
    }
	@Override
	public int compareTo(Hero anotherHero) {
        if(damage<anotherHero.damage)
            return 1; 
        else
            return -1;
    }
	public boolean matched(){
		   return this.hp>100 && this.damage<50;
		}
	public void attackHero(Hero h) {
    
            //为了表示攻击需要时间,每次攻击暂停1000毫秒
         //   Thread.sleep(1000);
        
        h.hp-=damage;
        System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n",name,h.name,h.name,h.hp);
         
        if(h.isDead())
            System.out.println(h.name +"死了!");
    }
 
    public boolean isDead() {
        return 0>=hp?true:false;
    }
    public void BoDongQuan() {//波动拳技能
    	while(true) {
    		for(int i =0;i<3;i++) {
    		 System.out.printf("波动拳第%d发\n",i+1);
    		 try {
				Thread.sleep(1000);//每隔一秒发一次
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    		System.out.println("开始为时5秒的充能");
    		try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			
				e.printStackTrace();
			}
    	}

}
    public  static void main(String [] args) {
       Hero h =new Hero();
       h.BoDongQuan();
    }
}

							





回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2019-04-29 为什么只有第一个线程执行了?第二个没有。
2019-04-23 交作业(二),欢迎暂时没思路的朋友来交流参考
2019-04-10 服了你们,提问的地方,一个个的来交作业了,秀呢?
2019-03-31 作业1
2019-03-29 作业1
2019-03-26 波动拳作业
2019-03-25 作业二
2019-03-25 作业1
2019-03-25 作业一
2019-03-23 提交作业
2019-03-21 波动拳作业
2019-03-06 作业1
2019-03-03 作业2
2019-03-02 作业1
2019-02-24 作业
2019-02-07 为什么removeLast会报异常 removeFirst不会
2019-01-26 破解密码 for循环
2019-01-17 交作业
2018-12-27 交作业
2018-12-13 示例三和示例四,copy的代码,在程序运行的时候可以看到盖伦打提莫和赏金打盲僧,可是运行完之后在控制台只能看到赏金打盲僧,另一个进程的显示没了是为什么?
2018-11-30 作业:穷举法破解密码
2018-11-30 作业: 波动拳
2018-11-22 波动拳小改一下
2018-11-22 穷举破解随机密码作业
2018-11-12 破解密码代码
2018-10-25 String password = passwords.remove(0);
2018-10-09 作业疑问
2018-10-09 破解密码
2018-09-05 交作业 作业2
2018-09-04 练习2中的问题
2018-09-04 我好像投机了
2018-08-30 作业2!!
2018-08-30 波动拳作业!改!
2018-08-19 case 1:波动拳作业
2018-08-08 private list为什么可以共享
2018-08-08 作业
2018-08-05 波动拳
2018-07-31 交作业
2018-07-27 如何在守护进程(t0)中停止其他进程? 进而停止程序?
2018-07-22 英雄充能
2018-06-22 波动拳代码。
2018-06-13 加入线程到main中 的条件是在开启下一个线程之前进行 t1.join()吗?
2018-06-11 实例6英雄充能 可以这样写吗? 感觉有点问题
2018-06-09 【破解密码】使用 LinkedList 记录 Log 时出现的空指针异常
2018-05-26 求助
2018-05-08 第一个例子不是会死循环么?
2018-04-21 if (found) return; 再代码中起什么作用啊?希望会的大神帮忙
2018-04-14 最后一个密码破解题有个奇怪现象
2018-04-08 作业1,波动拳三次,不知道这个算不算对啊?
2018-04-04 破解密码 一个很需要解答的问题,自己找bug快疯了
2018-04-01 交作业
2018-02-18 关于守护线程的问题,将谁设置成守护线程才对
2017-12-12 跳过第一个线程,直接进行第二个线程?
2017-11-27 匿名类的实现方案是什么样的
2017-08-04 设置线程优先级,测试结果一次正常,一次没有体现出设置的优先级??
2017-08-02 在实验示例三的时候,打印的结果里有乱码
2017-06-12 示例7的答案中一个疑问
2017-06-08 join作用问题
2017-06-06 一个错别字哈哈哈
2017-04-21
2016-12-21 关于示例 1 : 当前线程暂停
2016-07-17 还没有打印出 找到密码 守护进程就结束了 求解决




提问之前请登陆
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
关于 JAVA 中级-多线程-常见线程方法 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 1001964108
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: http://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图