Java基础面试题题库积累

多线程两种实现方式

(1)继承Thread
* 定义类继承Thread
* 重写run方法
* 把新线程要做的事写在run方法中
* 创建线程对象
* 开启新线程, 内部会自动执行run方法
(2)实现Runnable
* 定义类实现Runnable接口
* 实现run方法
* 把新线程要做的事写在run方法中
* 创建自定义的Runnable的子类对象
* 创建Thread对象, 传入Runnable
* 调用start()开启新线程, 内部会自动调用Runnable的run()方法
*

多线程的安全问题及解决方案

问题:当多线程并发, 有多段代码同时执行时,数据会产生错乱。
方案:我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步。

死锁的产生原理

多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁

多线程两种实现方式的区别

实现原理:
继承Thread	:	由于子类重写了Thread类的run(), 当调用start()时, 直接找子类的run()方法
实现Runnable:	构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run()方法时内部判断成员变量Runnable的引用是否为空, 不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法

优缺点:
继承Thread :
好处: 可以直接使用Thread类中的方法,代码简单
弊端: 如果已经有了父类,就不能用这种方法
实现Runnable:
好处: 即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
弊端: 不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂

单例设计模式,适配器设计模式

单例设计模式:	
	在java中,单例模式是指为了保证类在内存中只有一个对象,而形成的一种固有的代码模式!
适配器设计模式:
	在java中,适配器设计模式是指为了监视某些行为,但是对于每种监听到的行为又有不同的处理,为了能够让监听者自行来处理监听到指定行为后,要做的后续操作,而形成的一种固有的代码模式!

适配器标准课上答案:
	* a.什么是适配器
		* 在使用监听器的时候, 需要定义一个类事件监听器接口.
		* 通常接口中有多个方法, 而程序中不一定所有的都用到, 但又必须重写, 这很繁琐.
		* 适配器简化了这些操作, 我们定义监听器时只要继承适配器, 然后重写需要的方法即可.
	* b.适配器原理
		* 适配器就是一个类, 实现了监听器接口, 所有抽象方法都重写了, 但是方法全是空的.
		* 适配器类需要定义成抽象的,因为创建该类对象,调用空方法是没有意义的
		* 目的就是为了简化程序员的操作, 定义监听器时继承适配器, 只重写需要的方法就可以了.

饿汉式和懒汉式的区别

使用场合:
饿汉式: 开发用
懒汉式: 面使用,开发一般不用
思想:
饿汉式: 类一加载就生成对象。
懒汉式: 在调用获取对象的方法的时候生成。
实用性:
饿汉式: 安全,效率高。相对懒汉式会在未使用之前就占用内存。
懒汉式: 存在线程安全漏洞,可以利用同步解决,但是效率会变低。内存方面符合了编程中的延迟加载思想。(在面试中面试官会比较希望答出这一点)

Timer类是干嘛的

Timer类是计时器。
一般的使用过程是在Timer类的schedule()方法中传入两个参数,一个TimerTask的子类对象,在这个子类对象中规定了计时结束的操作,另一个java.util.Date类的对象,其参数指定了计时的开始时间和循环周期,

wait和sleep的区别

sleep方法:定义在Thread类中,让线程在指定时间内处于休眠状态,超时后继续向下执行,休眠的线程不会释放锁资源。
wait方法 :定义在Object类中,让以当前对象为监视器的线程处于阻塞状态,不可获取执行权,在得到notify或者notifyAll的通知后再继续抢夺执行权。等待的线程会释放锁资源。

线程的生命周期(五中状态的切换流程)

线程分为5个生命周期,新建,就绪,运行,阻塞,死亡
其中:
新建代表线程在内存中创建,对应start方法。
就绪代表线程拥有抢夺执行权的资格,如果抢到就会执行线程中的内容
运行代码线程中的内容正在执行。
a:若被抢走执行权,回到就绪状态
b:若执行ssleep、wait等方法,会进入阻塞状态。
阻塞代表线程被强制不可进入就绪状态,对于非就绪状态的线程是没有机会抢夺执行权,也就更不可能进入运行状态了。
死亡代表线程运行结束,也可能是被强制结束,一般不建议使用。

网络三要素

IP

* 每个设备在网络中的唯一标识
* 每台网络终端在网络中都有一个独立的地址,我们在网络中传输数据就是使用这个地址。 
* ipconfig:查看本机IP192.168.12.42
* ping:测试连接192.168.40.62
* 本地回路地址:127.0.0.1 255.255.255.255是广播地址
* IPv4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。 
* IPv6:8组,每组4个16进制数。

端口

* 每个程序在设备上的唯一标识
* 每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。
* 端口号范围从0-65535
* 编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
* 常用端口
	* mysql: 3306
	* oracle: 1521
	* web: 80
	* tomcat: 8080
	* QQ: 4000
	* feiQ: 2425

协议:(udp和tcp的区别)

* 为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
* UDP
	* 面向无连接,数据不安全,速度快。不区分客户端与服务端。
* TCP
  * 面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。
	* 三次握手: 客户端先向服务端发起请求, 服务端响应请求, 传输数据

UDP和TCP的传输过程

udp传输过程

* a.发送Send
	* 创建DatagramSocket, 随机端口号
	* 创建DatagramPacket, 指定数据, 长度, 地址, 端口
	* 使用DatagramSocket发送DatagramPacket
	* 关闭DatagramSocket
* b.接收Receive
	* 创建DatagramSocket, 指定端口号
	* 创建DatagramPacket, 指定数组, 长度
	* 使用DatagramSocket接收DatagramPacket
	* 关闭DatagramSocket
	* 从DatagramPacket中获取数据
* c.接收方获取ip和端口号
	* String ip = packet.getAddress().getHostAddress();
	* int port = packet.getPort();

tcp的传输过程

* a.客户端
	* 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
	* 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
	* 输入流可以读取服务端输出流写出的数据
	* 输出流可以写出数据到服务端的输入流
* b.服务端
	* 创建ServerSocket(需要指定端口号)
	* 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
	* 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
	* 输入流可以读取客户端输出流写出的数据
	* 输出流可以写出数据到客户端的输入流

编程题

抽奖池

有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池用一个数组int[] arr = {10,5,20,50,100,200,500,800,2,80,300};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”,随机从arr数组中获取奖项元素并打印在控制台上,格式如下:

抽奖箱1 又产生了一个 10 元大奖
抽奖箱2 又产生了一个 100 元大奖	
//.....

//未实现交替产生

public class Test06 {
		public static void main(String[] args) {
			//创建实现Runnable接口的实现类对象
			ChouJiang cj = new ChouJiang();
			//创建两个线程并开启
			new Thread(cj,"抽奖箱1").start();
			new Thread(cj,"抽奖箱2").start();		
		}
	}
	class ChouJiang implements Runnable {
		private int[] arr = {10,5,20,50,100,200,500,800,2,80,300};
		private int num = arr.length;
		private ArrayList<Integer> list =  new ArrayList<Integer>();
		@Override
		public void run() {
			String threadName = Thread.currentThread().getName();
			while(true) {
				synchronized(this){
					if(num<=0)
						break;
					//创建随机数对象
					Random r = new Random();
					int index ;
					//为了获取不重复的索引值
					while(true) {
						index = r.nextInt(arr.length);
						if(list.contains(index))
							continue;
						else {
							list.add(index);
							break;
						}
					}
					int money = arr[index];
					System.out.println(threadName + " 又产生了一个 "+money+" 元大奖");
					num--;
				}
			}
			
		}
		
	}
	//实现交替产生
	public class Test06_02 {
		public static void main(String[] args) {
			//创建实现Runnable接口的实现类对象
			ChouJiang2 cj = new ChouJiang2();
			//创建两个线程并开启
			new Thread(cj,"抽奖箱1").start();
			new Thread(cj,"抽奖箱2").start();		
		}
	}
	class ChouJiang2 implements Runnable {
		private int[] arr = {10,5,20,50,100,200,500,800,2,80,300};
		private int num = arr.length;
		private ArrayList<Integer> list =  new ArrayList<Integer>();
		//标志作用就是轮流执行
		private boolean flag = true;
		@Override
		public void run() {
			String threadName = Thread.currentThread().getName();
			while(true) {
				synchronized(this){
					this.notifyAll();
					if(num<=0)
						break;
					//创建随机数对象
					Random r = new Random();
					int index ;
					//为了获取不重复的索引值
					while(true) {
						index = r.nextInt(arr.length);
						if(list.contains(index))
							continue;
						else {
							list.add(index);
							break;
						}
					}
					int money = arr[index];
					if(flag) {
						System.out.println(threadName + " 又产生了一个 "+money+" 元大奖");
						num--;
						flag = false;
	//					this.notifyAll();
						try {
							this.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						
					} else {
						System.out.println(threadName + " 又产生了一个 "+money+" 元大奖");
						num--;
						flag = true;
	//					this.notifyAll();
						try {
							this.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
			
		}
		
	}

年会入场

7、某公司组织年会,会议入场时有两个入口,在入场时每位员工都能获取一张双色球彩票,假设公司有100个员工,利用多线程模拟年会入场过程,
并分别统计每个入口入场的人数,以及每个员工拿到的彩票的号码。线程运行后打印格式如下:
编号为: 2 的员工 从后门 入场! 拿到的双色球彩票号码是: [17, 24, 29, 30, 31, 32, 07]
编号为: 1 的员工 从后门 入场! 拿到的双色球彩票号码是: [06, 11, 14, 22, 29, 32, 15]
//…
从后门入场的员工总共: 13 位员工
从前门入场的员工总共: 87 位员工
//产生双色球的工具类已经给出(此代码不要求掌握,只是方便大家在多线程中调用)

public class DoubleColorBallUtil {
	
		public static String[] creates(int num){
			String[] arr = new String[num];
			for(int i = 0;i<num;i++) {
				arr[i] = DoubleColorBallUtil.create();
			}
			return arr;
		}

		//产生双色球的代码
		public static String create() {		
			String[] red = {"01","02","03","04","05","06","07","08","09","10",
					"11","12","13","14","15","16","17","18","19","20","21","22","23",
					"24","25","26","27","28","29","30","31","32","33"};
			/*//创建红球
			for(int i=0;i<red.length;i++) {
				char[] ch = {'0','0'};
				String s = Integer.toString(i+1);//"1"
				char[] num = s.toCharArray();//{'1'}
				System.arraycopy(num, 0, ch, ch.length-num.length, num.length);
				String ball = new String(ch);
				red[i] = ball;			
			}*/
			
			//System.out.println(Arrays.toString(red));//打印01-33
			//创建蓝球
			String[] blue = "01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16".split(",");
			boolean[] used = new boolean[red.length];
			Random r = new Random();
			String[] all = new String[7];
			for(int i = 0;i<6;i++) {
				int idx;
				do {
					idx = r.nextInt(red.length);//0-32
				} while (used[idx]);//如果使用了继续找下一个
				used[idx] = true;//标记使用了
				all[i] = red[idx];//取出一个未使用的红球			
			}
			all[all.length-1] = "99";
			//System.out.println(Arrays.toString(all));
			Arrays.sort(all);
			all[all.length-1] = blue[r.nextInt(blue.length)];
			return Arrays.toString(all);
		}
	}

	public class Test07_01 {
		public static void main(String[] args) {
			//测试产生双色球的代码
	//		String doubleColorBallNumber = DoubleColorBallUtil.create();
	//		System.out.println(doubleColorBallNumber);
			//1.创建实现Runnable接口的实现类对象
			NianHui nh = new NianHui();
			//2.创建线程并启动
			new Thread(nh,"后门").start();
			new Thread(nh,"前门").start();
		}
	}
	/**
	 * 需要线程同步
	 * 1.多线程操作共享数据
	 * 2.操作共享数据的语句有两条以上
	 * @author JX
	 *
	 */
	class NianHui implements Runnable {
		private int num = 100;
		@Override
		public void run() {
			//获取当前线程的名称
			String threadName = Thread.currentThread().getName();
			while(true) {
				synchronized (this) {
					//num<=0,线程终止
					if(num<=0)
						break;
					//产生双色球
					String doubleColorBallNumber = DoubleColorBallUtil.create();
					System.out.println("编号为: "+(num--)+" 的员工 从"+threadName+" 入场! 拿到的双色球彩票号码是: "+doubleColorBallNumber);
				}
			}
		}
		
	}
	
	public class Test07_02 {
		public static void main(String[] args) {
			//测试产生双色球的代码
	//		String doubleColorBallNumber = DoubleColorBallUtil.create();
	//		System.out.println(doubleColorBallNumber);
			//1.创建实现Runnable接口的实现类对象
			NianHui2 nh = new NianHui2();
			//2.创建线程并启动
			new Thread(nh,"后门").start();
			new Thread(nh,"前门").start();
		}
	}
	/**
	 * 需要线程同步
	 * 1.多线程操作共享数据
	 * 2.操作共享数据的语句有两条以上
	 * @author JX
	 *
	 */
	class NianHui2 implements Runnable {
		private int num = 100;
		private int hmCount = 0;
		private int qmCount = 0;
		@Override
		public void run() {
			//获取当前线程的名称
			String threadName = Thread.currentThread().getName();
			while(true) {
				synchronized (this) {
					//num<=0,线程终止
					if(num<=0) {
						if("后门".equals(threadName)) {
							System.out.println("从"+threadName+"入场的员工总共: "+hmCount+" 位员工");						
						} else {
							System.out.println("从"+threadName+"入场的员工总共: "+qmCount+" 位员工");
						}
						break;
					}
					//产生双色球
					String doubleColorBallNumber = DoubleColorBallUtil.create();
					if("后门".equals(threadName)) {
						hmCount++;
					} else {
						qmCount++;
					}
					System.out.println("编号为: "+(num--)+" 的员工 从"+threadName+" 入场! 拿到的双色球彩票号码是: "+doubleColorBallNumber);
				}
			}
		}
		
	}
	
	public class Test07_03 {
		public static void main(String[] args) {
			//测试产生双色球的代码
	//		String doubleColorBallNumber = DoubleColorBallUtil.create();
	//		System.out.println(doubleColorBallNumber);
			//1.创建实现Runnable接口的实现类对象
			NianHui3 nh = new NianHui3();
			//2.创建线程并启动
			new Thread(nh,"后门").start();
			new Thread(nh,"前门").start();
		}
	}
	/**
	 * 需要线程同步
	 * 1.多线程操作共享数据
	 * 2.操作共享数据的语句有两条以上
	 * @author JX
	 *
	 */
	class NianHui3 implements Runnable {
		private int num = 100;
		private int hmCount = 0;
		private int qmCount = 0;
		//产生100张彩票
		private String[] arr = DoubleColorBallUtil.creates(100);
		@Override
		public void run() {
			//获取当前线程的名称
			String threadName = Thread.currentThread().getName();
			while(true) {
				synchronized (this) {
					//num<=0,线程终止
					if(num<=0) {
						if("后门".equals(threadName)) {
							System.out.println("从"+threadName+"入场的员工总共: "+hmCount+" 位员工");						
						} else {
							System.out.println("从"+threadName+"入场的员工总共: "+qmCount+" 位员工");
						}
						break;
					}
					//从数组中随机获取一张双色球
					//1.先随机获取一个索引
					Random r = new Random();
					int index = r.nextInt(100);
					String doubleColorBallNumber = arr[index];
					if("后门".equals(threadName)) {
						hmCount++;
					} else {
						qmCount++;
					}
					System.out.println("编号为: "+(num--)+" 的员工 从"+threadName+" 入场! 拿到的双色球彩票号码是: "+doubleColorBallNumber);
				}
			}
		}
		
	}
	
	public class Test07_04 {
		public static void main(String[] args) {
			//测试产生双色球的代码
	//		String doubleColorBallNumber = DoubleColorBallUtil.create();
	//		System.out.println(doubleColorBallNumber);
			//1.创建实现Runnable接口的实现类对象
			NianHui4 nh = new NianHui4();
			//2.创建线程并启动
			new Thread(nh,"后门").start();
			new Thread(nh,"前门").start();
		}
	}
	/**
	 * 需要线程同步
	 * 1.多线程操作共享数据
	 * 2.操作共享数据的语句有两条以上
	 * @author JX
	 *
	 */
	class NianHui4 implements Runnable {
		private int num = 100;
		//产生100张彩票
		private String[] arr = DoubleColorBallUtil.creates(100);
		@Override
		public void run() {
			//获取当前线程的名称
			String threadName = Thread.currentThread().getName();
			int count = 0;
			while(true) {
				synchronized (this) {
					//num<=0,线程终止
					if(num<=0) {
						break;
					}
					//从数组中随机获取一张双色球
					//1.先随机获取一个索引
					Random r = new Random();
					int index = r.nextInt(100);
					String doubleColorBallNumber = arr[index];
					System.out.println("编号为: "+(num--)+" 的员工 从"+threadName+" 入场! 拿到的双色球彩票号码是: "+doubleColorBallNumber);
					count++;
				}
			}
			System.out.println("从"+threadName+"入场的员工总共: "+count+" 位员工");
		}
		
	}
	
	
``
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃掉你的脑子·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值