创建线程其他知识点

网友投稿 554 2022-05-29

前两篇博客我写了有关创建线程以及创建线程池的方法,这篇博客用来总结JAVA多线程实战第一章创建线程的其他内容,一些创建和使用线程的知识点。

一、Thread类和Runnable接口的区别

之前讲的创建线程的四种方法中前两中方法分别是通过继承Thread类和实现Runnable接口创建线程,这两种方法是创建线程的最常用方法,那两者有什么区别?

直接通过代码演示。

public class MyThread extends Thread{ private int ticket = 10; public MyThread(String name) { super(name); } @Override public void run() { while(true) { if(ticket>0) { System.out.println(Thread.currentThread().getName()+"卖出第"+(10-ticket--+1)+"张门票"); } } } } public class MyThreadTest { public static void main(String[] args) { // TODO Auto-generated method stub MyThread mt1 = new MyThread("窗口一"); MyThread mt2 = new MyThread("窗口二"); MyThread mt3 = new MyThread("窗口三"); mt1.start(); mt2.start(); mt3.start(); } }

public class MyRunnable implements Runnable{ private int ticket = 10; @Override public void run() { // TODO Auto-generated method stub while(true) { if(ticket>0) { System.out.println(Thread.currentThread().getName()+"卖出"+(10- ticket-- +1)+"张票"); } } } } public class MyRunnableTest { public static void main(String[] args) { // TODO Auto-generated method stub MyRunnable mr = new MyRunnable(); Thread t1 = new Thread(mr,"窗口一"); Thread t2 = new Thread(mr,"窗口二"); Thread t3 = new Thread(mr,"窗口三"); t1.start(); t2.start(); t3.start(); } }

继承Thread类创建线程的运行结果是三个线程独立进行,不共享资源。所以可知,这种方法创建线程不共享资源

实现Runnable接口的运行结果是三个线程共享资源,可以把Runnable当成资源,多线程共享资源

二、线程start和run方法的区别

通过代码演示

public class UseThread extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName()+",执行run方法"); } } public class UserThreadTest { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println(Thread.currentThread().getName()+" 执行main方法"); UseThread useThread = new UseThread(); useThread.run();//只有一个线程再执行,是单线程的 useThread.start();//创建一个新线程 } }

根据运行结果可以看出,使用run()方法时,程序是单线程,只有主线程main在执行任务,run()方法的内容也是有主线程执行,并没有新建线程执行run()方法

使用start()方法后,run()方法里的内容被新建的线程执行。

所以如果想新建线程,那就要用start()方法

三、线程的优先级

JAVA默认情况下线程是有轮流使用CPU的特权,平均分配给每个线程占用CPU的使用时间,但是设置优先级后就不一样了

有关线程优先级的知识点

Java的优先级是从1-10,默认优先级是5,10最高。

主线程main的优先级是5

优先级高的线程占用CPU的概率大,但是优先级低的线程并不是没有机会执行,只是概率问题

即使设置了优先级,也无法保证线程的执行顺序,只是概率问题

public class UserRunnable implements Runnable{ @Override public void run() { for(int i = 0;i<10;i++) { System.out.println(Thread.currentThread().getName()+"第"+i+"次执行"); } } } public class UserThread extends Thread{ @Override public void run() { for(int i = 0;i<10;i++) { System.out.println(Thread.currentThread().getName()+"第"+i+"次执行"); } } } public class Test { public static void main(String[] args) { // TODO Auto-generated method stub UserThread ut = new UserThread(); UserRunnable ur = new UserRunnable(); Thread t = new Thread(ur); ut.setPriority(1); t.setPriority(10); ut.start(); t.start(); } }

四、定时线程的任务调度

调用定时线程有两种方法,分别是schedule()和scheduleAtFixedRate(),两者区别是前者特点为延时不追加执行任务,后者特点为延时追加任务。这两个特点的含义是什么呢?

延时不追加任务:当前系统时间已经超过了设置时间,线程从当前时间执行任务。当前时间没到设置时间,线程会等时间到了再执行任务

创建线程的其他知识点

延时追加任务:当前系统时间已经超过了设置时间,线程会将当前时间和设置时间组差,根据设置的任务执行间隔算出少执行多少次人物,补充之前少的执行结果

五、接口同步回调和异步回调

同步调用:一种阻塞式调用,调用方要等待对方执行完才能返回,它是一种单向调用,平时我们调用方法就是同步调用

回调:一种双向调用模式,被调用方在接口被调用时也会调用对方接口

异步调用:一种类似事件或消息机制,不过他的调用方向刚好相反,接口的服务在接收到某种讯息或者发生某种事件会主动通知客户端。不需要等待对方执行完再返回

第一种情况

public interface Callback { public void process(String msg); } public class MyCallback implements Callback{ @Override public void process(String msg) { // TODO Auto-generated method stub System.out.println("处理成功,返回状态为: "+msg); } }//这个方法就是回调函数,客户端给服务端输入信息,通过回调函数告知客户端信息已被处理 public class Server { public void getMsg(Callback callback,String msg) throws InterruptedException { System.out.println("服务器端已接收到信息:"+msg); //模拟消息处理,等待两分钟 Thread.sleep(2000); System.out.println("消息已经被处理,返回状态为:"+msg); //处理完消息,调用客户端,已经处理好消息 callback.process(msg); }//获取服务器端消息并且对消息进行处理,再告诉客户端你的消息已经被处理成功了 } public class Client { Server server; public Client(Server server) { this.server = server; } public void sendMsg(String msg) throws InterruptedException { System.out.println("客户端发出消息:"+msg); server.getMsg(new MyCallback(), msg); System.out.println("客户端已发出,等待处理"); } } public class Test1 { public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub Server s = new Server(); Client c = new Client(s); c.sendMsg("200"); } }

这种就是调用方法,也就是同步回调,输出结果如下:

客户端发出消息:200

服务器端已接收到信息:200

消息已经被处理,返回状态为:200

处理成功,返回状态为: 200

客户端已发出,等待处理

可以看出这个输出结果的顺序不是我们想要的,因为程序在等getMsg执行完才会往下执行

解决方法,在客户端创建线程是

public class Client { Server server; public Client(Server server) { this.server = server; } public void sendMsg(String msg) throws InterruptedException { System.out.println("客户端发出消息:"+msg); // server.getMsg(new MyCallback(), msg); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { server.getMsg(new MyCallback(), msg); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start();; System.out.println("客户端已发出,等待处理"); } }

这次的执行结果就符合预期

客户端发出消息:200

客户端已发出,等待处理

服务器端已接收到信息:200

消息已经被处理,返回状态为:200

处理成功,返回状态为: 200

创建线程后就各干各的,不用等一个做完才能做下一个

六.总结

好啦,第一章全部总结完毕,希望能给其他学习java的伙伴带来一定关注,后续还会继续更新

Java 培训服务

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:网络协议 概念
下一篇:快来看神仙打架啊
相关文章