互联网面试总结(一) : 程序题

多线程

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



原文地址:https://www.cnblogs.com/evan-liang/p/12233973.html