1.使用callable接口实现多线程
我们继续用这个多线程来实现龟兔赛跑:
package callable; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 我们用callable来模拟一下龟兔赛跑 * * @author Wang * */ public class Demo { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService ser = Executors.newFixedThreadPool(2);//这里就是创建两个线程 Race tortoise = new Race("乌龟",1000);//1s走一步 Race rabbit = new Race("小兔子",500);//0.5s Future<Integer> result1 =ser.submit(tortoise) ;//获取线程体返回过来的值 要用对应的类型进行接收 Future<Integer> result2 =ser.submit(rabbit) ; Thread.sleep(2000); //2秒 让线程运行两秒 tortoise.setFlag(false); //停止线程体循环 rabbit.setFlag(false); int num1 =result1.get(); //注意这个地方要接收值 int num2 =result2.get(); System.out.println("乌龟跑了-->"+num1+"步"); System.out.println("小兔子跑了-->"+num2+"步"); //停止服务 ser.shutdownNow();//关闭线程 } } class Race implements Callable <Integer> {//这里的Integer的作用是返回的是Interger类型的 private String name; //创建的这个线程叫什么名字 private long time; //多长时间走一步 private boolean flag = true;//标志位 private int step;//走了多少步 public Race() { } public Race(String name, long time) { super(); this.name = name; this.time = time; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getTime() { return time; } public void setTime(long time) { this.time = time; } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public int getStep() { return step; } public void setStep(int step) { this.step = step; } @Override public Integer call() throws Exception { while(flag) { Thread.sleep(time);//程序睡眠多长时间 就是相当于多长时间走了一步 step++; } return step; } }
2.线程的状态:
2.线程的停止:
package Stop; /** * * 外部干涉来停止线程 * * @author Wang * */ public class StopDemo01 { public static void main(String[] args) throws InterruptedException { run r = new run();//搞清楚谁是实体 new Thread(r).start();//这里使用的是匿名类 for(int i=0;i<30;i++) { if(i==10) { //外部根据条件来调用停止对方法; r.stop(); } System.out.println(i); } } } class run implements Runnable{ private boolean flag = true;//定义线程体中使用的标识 @Override public void run() { while(flag) {//线程体使用该标识 System.out.println("线程ing....."); } } void stop() {//提供外部的方法来改变标识 flag = false; yi } }注意:其实Thread类(代理)里面也有线程停止的方法只不过这些方法,不推荐使用,主要是这些方法不安全;
3.线程的阻塞:
1.join():合并线程
package Stop; /** * * 线程的阻塞 Join * * @author Wang * */ public class JoinDemo01 extends Thread { public static void main(String[] args) throws InterruptedException { JoinDemo01 j = new JoinDemo01();//新生 Thread t = new Thread(j); t.start();//就绪 //cpu运行调度 for(int i=0;i<200;i++) { if(i==50) { t.join();//这里会把两个线程合为一个 会继续执行t但是变为了单线程 他执行玩以后在执行main()函数 所以我们就说main函数被阻塞; } System.out.println("main运行" + i); } } public void run() {// 重写run()方法 这个就是线程体 for (int i = 0; i < 200; i++) { System.out.println("执行j" + i); } } }
2.yield():暂停自己的线程 static
package Stop; /** * * 测试Yield * * @author Wang * */ public class Yield extends Thread{ public static void main(String[] args) { Yield y = new Yield(); Thread t = new Thread(y); t.start(); for(int i=0;i<50;i++) { if(i==10) { Thread.yield();//他是一个静态方法 在哪个线程里调用就会暂停那个线程 这个暂停只是暂停一瞬间 } System.out.println("main" + i); } } public void run() {// 重写run()方法 这个就是线程体 for (int i = 0; i < 100; i++) { System.out.println("执行y" + i); } } }3.sleep();睡眠 static,不释放锁(常用的方法)
one:与时间相关(模拟倒计时)
two:模拟网络延时
package Stop; import java.text.SimpleDateFormat; import java.util.Date; /** * * 测试一下sleep的用法 * * @author Wang * */ public class sleep { public static void main(String[] args) throws InterruptedException {//写一个当前时间的倒计时 Date endTime = new Date(System.currentTimeMillis()+10*1000);//得到倒计时的开始时间 当前时间10s后的时间 long end = endTime.getTime(); while(true) { System.out.println(new SimpleDateFormat("mm:ss").format(endTime));//将这个时间格式化为字符串类型 采用了匿名类 这里给你所在的地区时间不太一致是牵涉到时区的问题 Thread.sleep(1000); endTime = new Date(endTime.getTime() - 1000); if(end-10000 >= endTime.getTime()) {//倒计时10后跳出 break; } } } }
看一下网络延时给我们带来的问题:
package Stop; import Runnable.Web; /** * * 来看一下网络延时所带来的问题 * * @author Wang * */ public class SleepDemo02 implements Runnable{ private int ticketNum = 50; @Override public void run() { while(true) { if(ticketNum<0) { break; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "抢到了" + ticketNum--); } } public static void main(String[] args) { SleepDemo02 web = new SleepDemo02();//创建实体对象 Thread thr1 = new Thread(web,"路人甲");//创建四个代理 他们来实现多线程的抢票 Thread thr2 = new Thread(web,"黄牛"); Thread thr3 = new Thread(web,"程序员"); Thread thr4 = new Thread(web,"白领"); thr1.start(); thr2.start(); thr3.start(); thr4.start(); } }
从这张图上我们可以看到抢票抢到-1的情况
看这里当最后一次抢票的时候,这时候票还剩两张,我们第一个代理和第二个代理都会进去while() 但是他们会休眠所以num还是大于0的 不跳出循环 这样我们的另外两个代理都会进入程序中,就会拿到0和-1;
4.测试currentThread()
package priority; /** * * 自己写一个线程的实体 * * @author Wang * */ public class MyThread implements Runnable{ private int num = 0; private boolean flag = true; @Override public void run() { while(flag) { System.out.println(Thread.currentThread().getName() + num++);//得到当前线程的名字; } } public void stop() { flag = false; } }
package priority; /** * * 我们来测试一下这个类 * * @author Wang * * Thread.currentThread() :当前线程 * setName():设置名称 * getName():获取名称 * isAlive():判断状态 * */ public class currentThread { public static void main(String[] args) throws InterruptedException { MyThread mt = new MyThread();//创建一个是实体 Thread proxy = new Thread(mt,"wang"); proxy.setName("wanga");//更改线程的名字 System.out.println(proxy.getName()); System.out.println(Thread.currentThread().getName());//获取当前线程的名字 在这里应该是Main proxy.start(); System.out.println(proxy.isAlive()); Thread.sleep(5); mt.stop(); Thread.sleep(5);// 这里需要延时一下 给线程一个关闭的时间; System.out.println(proxy.isAlive()); } }
5.测试priority()
package priority; /** * * 我们来了解一下线程优先级的问题 * 优先级:概率,不是绝对的先后顺序 * MAX_PRIORITY 10 * NORM_PRIORITY 5 (默认的优先级是这个) * MIN_PRIORITY 1 * * setPriority() * getPriority() * * @author Wang * */ public class PriorityDemo01 { public static void main(String[] args) throws InterruptedException { MyThread mt =new MyThread(); Thread p1 =new Thread(mt,"aione"); MyThread mt2 =new MyThread(); Thread p2 =new Thread(mt2,"aitwo"); p1.setPriority(Thread.MIN_PRIORITY); //设置优先级 p2.setPriority(Thread.MAX_PRIORITY);//设置优先级 他的优先级高 那么他执行的概率就比较大 p1.start(); p2.start(); Thread.sleep(1); mt.stop(); mt2.stop(); } }
注意:我们学习java的基本知识就是学类和接口的;
线程的优先级高 就是执行他的概率大一点 而不是先执行优先级高的 在执行优先级低的;