创建线程的其他知识点

举报
小高先生 发表于 2022/05/23 22:22:29 2022/05/23
【摘要】 创建线程的其他知识点

  前两篇博客我写了有关创建线程以及创建线程池的方法,这篇博客用来总结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的伙伴带来一定关注,后续还会继续更新

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。