超链接没有反应
607
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小时内删除侵权内容。