java面试题之多线程和并发库

1、多线程实现方式

    (1)使用类Thread

    在Thread子类覆盖的run方法中编写运行代码

         new Thread() {
    @Override
    public void run() {
    while(true) {
    try {
    Thread.sleep(2000);
   
    catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }.start();

    (2)实现Runnable接口

   在传递给Thread对象的Runnable对象的run方法中编写代码

2 线程局部变量ThreaLocal

    (1)ThreadLocal 的作用和目的:

        ThreadLocal用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另外一个线程中运行时又共享另外一份数据。

        (2)每个线程调用ThreadLocal对象的set方法,在set方法中,首先根据当前线程获取当前线程的ThreadLocalMap对象,然后往这个map中插入一条记录,key其实是ThreadLocal对象,value是各自的set方法传进去的值。也就是每个线程其实都有一份自己独享的ThreadLocalMap对象,该对象的Key是ThreadLocal对象,值是用户设置的具体值。在线程结束时可以调用ThreadLocal.remove()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。

        (3)ThreadLocal 的应用场景:
➢ 订单处理包含一系列操作:减少库存量、增加一条流水台账、修改总账,这几个操作要在同一个
事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败了,则应该把前面
的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码
分别位于不同的模块类中。
➢ 银行转账包含一系列操作: 把转出帐户的余额减少,把转入帐户的余额增加,这两个操作要在
同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同
的帐户对象的方法。
➢ 例如 Strut2 的 ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据是每
个线程各自的状态和数据,对于不同的线程来说,getContext 方法拿到的对象都不相同,对同一个
线程来说,不管调用 getContext 方法多少次和在哪个模块中 getContext 方法,拿到的都是同一

个。

        (4)ThreadLocal的使用方式

            ①在关联数据类中创建private static ThreadLoacal

            public class SerialNum {// The next serial number to be assigned
        private static int nextSerialNum = 0;
        private static ThreadLocal serialNum = new ThreadLocal() {
    protected synchronized Object initialValue() {
return new Integer(nextSerialNum++);
}
};
public static int get() {
return ((Integer) (serialNum.get())).intValue();
}
}

           ②在Util类中创建ThreadLocal

public class HibernateUtil {
private static Log log = LogFactory.getLog(HibernateUtil.class);
private static final SessionFactory sessionFactory; //定义SessionFactory
static {
try {
// 通过默认配置文件 hibernate.cfg.xml 创建SessionFactory 
sessionFactory = new Configuration().configure().buildSessionFactory()
} catch (Throwable ex) {
log.error("初始化 SessionFactory 失败!", ex);
throw new ExceptionInInitializerError(ex);
}
}


//创建线程局部变量 session,用来保存 Hibernate 的 Session
public static final ThreadLocal session = new ThreadLocal();
/**
* 获取当前线程中的 Session
* @return Session
* @throws HibernateException
*/
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// 如果 Session 还没有打开,则新开一个 Session
if (s == null) {
s = sessionFactory.openSession();session.set(s); //将新开的 Session 保存到线程局部变量中
}
return s;
}


public static void closeSession() throws HibernateException {
//获取线程局部变量,并强制转换为 Session 类型
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}

}

        ③在Runnable中创建ThreadLocal

在线程类内部创建 ThreadLocal,基本步骤如下:

        a、在多线程的类(如 ThreadDemo 类)中,创建一个 ThreadLocal 对象 threadXxx,用来保存线程间需要隔离处理的对象 xxx。

        b、在 ThreadDemo 类中,创建一个获取要隔离访问的数据的方法 getXxx(),在方法中判断,若ThreadLocal 对象为 null 时候,应该 new()一个隔离访问类型的对象,并强制转换为要应用的类型

        c、在 ThreadDemo 类的 run()方法中,通过调用 getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。


猜你喜欢

转载自blog.csdn.net/u014753629/article/details/79970462