zoukankan      html  css  js  c++  java
  • 互联网面试总结(一) : 程序题

    多线程

    1.如何用多线程去控制炸弹每隔2秒,4秒交替爆炸?(参考张孝祥)

    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class TimerThread {
    
    	static int count = 0;
    
    	public static void main(String[] args) {
    		// 如何用多线程去控制炸弹每隔2秒,4秒交替爆炸
    		class CustomizedTimerTask extends TimerTask {
    
    			@Override
    			public void run() {
    				// count是奇数时为0,偶数时为1
    				count = (++count) % 2;
    				System.out.println("Bomb!!!!,count="+count);
    				// count为0时,2秒触发,为1时,4秒触发,每次触发都会将count的值变为0
    				new Timer().schedule(new CustomizedTimerTask(), 2000 + 2000 * count);
    
    			}
    		}
    		//每2秒触发一次,每次触发都会将count的值变为1
    		new Timer().schedule(new CustomizedTimerTask(), 2000);
    		//打印相隔时间,可省略
    		while (true) {
    			System.out.println(new Date().getSeconds());
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    		}
    
    	}
    
    }
    

    执行结构:


    2.子线程打印10次,主线程打印100次,如此循环50次(参考张孝祥)



    3.在多线程运行时,实现多个模块在同一线程内共享数据,另外一条线程又共享另一份数据(参考张孝祥)

    分析:
    每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值。在线程结束时可以调用ThreadLocal.clear()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。
    ThreadLocal的应用场景:
    订单处理包含一系列操作:减少库存量、增加一条流水台账、修改总账,这几个操作要在同一个事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败了,则应该把前面的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码分别位于不同的模块类中。
     银行转账包含一系列操作: 把转出帐户的余额减少,把转入帐户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同的帐户对象的方法。
    例如Strut2的ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据是每个线程各自的状态和数据,对于不同的线程来说,getContext方法拿到的对象都不相同,对同一个线程来说,不管调用getContext方法多少次和在哪个模块中getContext方法,拿到的都是同一个。
    实验案例:定义一个全局共享的ThreadLocal变量,然后启动多个线程向该ThreadLocal变量中存储一个随机值,接着各个线程调用另外其他多个类的方法,这多个类的方法中读取这个ThreadLocal变量的值,就可以看到多个类在同一个线程中共享同一份数据。
    实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量。
    对基本类型的数据的封装,这种应用相对很少见。
    对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象。
    总结:一个ThreadLocal代表一个变量,故其中里只能放一个数据,你有两个变量都要线程范围内共享,则要定义两个ThreadLocal对象。如果有一个百个变量要线程共享呢?那请先定义一个对象来装这一百个变量,然后在ThreadLocal中存储这一个对象。
    


    package com.evanshare;
    
    import java.util.Random;
    
    public class ThreadlocalTest {
    	public static void main(String[] args) {
    		for (int i = 0; i < 10; i++) {
    			new Thread(new Runnable() {
    
    				@Override
    				public void run() {
    					// 绑定数据到当前线程
    					ThreadLocalData.getThreadLocalData().setData(new Random().nextInt());
    					System.out.println("线程:" + Thread.currentThread().getName() + ": has put data:"
    							+ ThreadLocalData.getThreadLocalData().getData());
    					// 多线程时,从A和B各自取出数据,如果同一条线程,put进去的数据和get的数据一致,则是正确
    					new A().get();
    					new B().get();
    
    				}
    			}).start();
    			;
    		}
    	}
    
    	// 把线程共享的变量和操作方法都封装在同一类中,方便维护
    	static class ThreadLocalData {
    
    		private Integer data = 0;
    
    		// 给线程共享的数据对外提供一个改变数值的方法
    		public void setData(Integer data) {
    			this.data = data;
    		}
    
    		// 获取线程共享的数据
    		public Integer getData() {
    			return this.data;
    		}
    
    		// 构造方法私有化,只在内部创建对象
    		private ThreadLocalData() {
    		}
    
    		private static ThreadLocal<Object> instanceContainer = new ThreadLocal<Object>();
    
    		public static ThreadLocalData getThreadLocalData() {
    			// 从threadLocal中取出绑定的对象
    			ThreadLocalData threaLocalData = (ThreadLocalData) instanceContainer.get();
    			//先判断当前实例是否存在,不存在则创建一个新的实例
    			if (threaLocalData == null) {
    				threaLocalData = new ThreadLocalData();
    				// 绑定 对象到trreaLocal中,使每条线程都有自己对应的线程内独立的共享数据
    				instanceContainer.set(threaLocalData);
    			}
    
    			return threaLocalData;
    		}
    
    	}
    
    	// 其他模块
    	static class A {
    		public void get() {
    			System.out.println("当前线程:" + Thread.currentThread().getName() + ":A==>data:"
    					+ ThreadLocalData.getThreadLocalData().getData());
    		}
    	}
    
    	// 其他模块
    	static class B {
    		public void get() {
    			System.out.println("当前线程:" + Thread.currentThread().getName() + ":B==>data:"
    					+ ThreadLocalData.getThreadLocalData().getData());
    		}
    	}
    
    }

    执行结果:
    线程:Thread-4: has put data:299256607
    线程:Thread-0: has put data:356189664
    线程:Thread-7: has put data:-1215289985
    线程:Thread-1: has put data:1718461731
    线程:Thread-6: has put data:1213215847
    线程:Thread-5: has put data:1144437339
    线程:Thread-2: has put data:-1851721218
    线程:Thread-8: has put data:1182402488
    线程:Thread-3: has put data:2050229878
    线程:Thread-9: has put data:-401592787
    当前线程:Thread-4:A==>data:299256607
    当前线程:Thread-5:A==>data:1144437339
    当前线程:Thread-2:A==>data:-1851721218
    当前线程:Thread-8:A==>data:1182402488
    当前线程:Thread-9:A==>data:-401592787
    当前线程:Thread-3:A==>data:2050229878
    当前线程:Thread-0:A==>data:356189664
    当前线程:Thread-7:A==>data:-1215289985
    当前线程:Thread-6:A==>data:1213215847
    当前线程:Thread-1:A==>data:1718461731
    当前线程:Thread-4:B==>data:299256607
    当前线程:Thread-0:B==>data:356189664
    当前线程:Thread-2:B==>data:-1851721218
    当前线程:Thread-7:B==>data:-1215289985
    当前线程:Thread-6:B==>data:1213215847
    当前线程:Thread-1:B==>data:1718461731
    当前线程:Thread-5:B==>data:1144437339
    当前线程:Thread-8:B==>data:1182402488
    当前线程:Thread-9:B==>data:-401592787
    当前线程:Thread-3:B==>data:2050229878
    



  • 相关阅读:
    JavaScript的函数(二)
    Python:os.walk()和os.path.walk()用法
    Python:代码单元、代码点介绍
    Python:如何去掉字符串中不需要的字符
    Python:更改字典的key
    Python:如何对字符串进行左、右、居中对齐
    Python:format()方法
    日常开发之缓存技术
    Web系统大规模并发——秒杀与抢购 秒杀系统优化与预防措施
    PHP之位运算符
  • 原文地址:https://www.cnblogs.com/evan-liang/p/12233973.html
Copyright © 2011-2022 走看看