您的位置:首页 > 编程语言 > Java开发

Java 并发编程知识点学习总结 (1)

2017-03-11 00:19 330 查看

Java 并发编程知识点学习总结 (1)

最近在清理思路,准备重新的阶段开始,想把自己过去学习的并发知识转入CSDN上来分享,也希望能得到大牛指点,不断更新学习笔记,欢迎直接留言交流,如转发请说明并附上链接,感谢!

开始:

0、线程类的定义方式

new Thread(); + 重写run()

implements Runnable; + 重写run()

1、对一个实现了Runnable接口的类来说,创建Thread对象并不会创建一个新的执行线程; 调用它的run()方法,也不会创建一个新的执行线程。只有调用它的start()方法时,才会创建一个新的执行线程。

2、线程的ID和status是不允许被修改的(getState()),线程类没有提供setId()和setStatus()方法来修改它们。

3、如果一个Thread是以Runnable对象为参数构建的,那么也可以使用Thread类的静态方法currentThread()来访问这个线程对象。

4、interrupt() interrupted() isInterrupted() 的使用

interrupt() 是用于设置线程对象的中断状态,在线程对象因使用sleep() wait()等方法随之抛出InterruptedException后,其中断状态就会被JVM自动清除,说明interrupt()操作只是用于设置线程对象的标志位(中断位)“Just to set the interrupt flag”。

interrupted() 是Thread的静态方法,在返回当前线程的中断状态标志位后,无论我们是否有通过中断异常的抛出,将立即清除这个中断状态标志位,第一次调用会得到true,第二次调用(因为状态已经清除)就是false,看源码便明白:

public void interrupt() {
if (this != Thread.currentThread())
checkAccess();

synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0();           // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}

public static boolean interrupted() {
return currentThread().isInterrupted(true);
}

public boolean isInterrupted() {
return isInterrupted(false);
}
// 返回的同时,按入参执行对线程状态位的清除
private native boolean isInterrupted(boolean ClearInterrupted);


isInterrupted() 是作用于调用该方法的线程对象所对应的线程,只是简单的查询中断状态,不会对状态标志位进行修改,留意源码:

return isInterrupted(false);


通常以interrupted()操作后,配合在执行线程中使用isInterrupted()判断,执行结束线程的逻辑,而不必抛出中断异常再去catch的处理方法。

参考贴:

http://blog.csdn.net/z69183787/article/details/25076033

5、在主线程逻辑中子执行线程调用 interrupt() 方法后,可以在主线程中对执行线程类thread.isInterrupted()方法确认是否中断,也可以在执行线程逻辑中用Thread.interrupted()来操作中断并得到状态,配合调用它的线程中使用throw new InterruptedException()添加需要的执行线程中断后的逻辑。

6、thread中睡眠功能使用sleep(1000),也可用TimeUtil.SECONDS.sleep(1)。

7、join()

join(int milliseconds)

join(int milli, int nonaseconds);

此3种使用的不同是,当一个线程在其逻辑中调用另一个线程的 join() 时,被调用线程执行结束后再会进行它后面的逻辑,而join(int milliseconds)相当于增加了一个复选条件,即当被调用线程执行结束 或者 调用join(int milli)后时钟到达了milli时间长度就继续运行它后续的逻辑。

8、setDaemon()方法只能在 start() 方法被调用前设置,isDaemon()检查是否守护线程。

9、run()方法没有throws语句;

所以不可能向上抛出异常,在一些未能预知异常的场景下,尤其是使用ExecutorService这类线程池控制实现时,上一层的调用方无法对run()的调用进行捕获,对于执行线程对象来说是直接打印堆栈并退出。

为防止线程溢出以及代码的健壮性和日志记录的完整性,应在执行线程的run()中分别结合使用 try{..}catch(){..} 和 setUncaughtExceptionHandler(UncaughtExceptionHandler exceptionHandler)方法来统一封装并初始化线程对象的运行时未知异常记录。

它能检测到这类异常而产生的线程终结,会通知线程池框架创建新的工作线程来替换,线程资源足够也可能不会,意味着控制了产生线程溢出的风险,并确保了ExcecutorService主线程的执行时配合log4j日志记录的完整(log4j的性能是另一个问题);

在ExecutorService使用下,要么在主线程中为每个执行线程设定setDefaultUncaughtExceptionHandler(),要么在执行线程中设定setUncaughtExceptionHandler()。才可能在执行器框架下有效。

另外,对于 ExecutorService 接口的实现,无论是 Executors.newFixedThreadPool()或Executors.newCachedThreadPool(),只有通过execute提交的任务,才能将它抛出的异常交给UncaughtExceptionHandler,而通过submit提交的任务,无论是抛出的未检测异常还是已检查异常,都将被认为是任务返回状态的一部分。如果一个由submit提交的任务由于抛出了异常而结束,那么这个异常将被Future.get封装在ExecutionException中重新抛出。

参考贴:

http://blog.csdn.net/u013256816/article/details/50417822

10、ThreadLocal varlidate = new ThreadLocal(); + 重写initialValue()方法,声明线程局部变量分别为每个线程存储了各自的属性值,并提供于各自使用,如果线程是第一次访问线程局部变量,线程局部变量可能还没有为它存储值,这个时候重写的initialValue()方法就会被调用,并返回当前线程的值;各线程私有变量的线程安全效果。可以remove()来清除局部变量存储值。其实关于ThreadLocal,有蛮多用处单独再写,它是笔者刚开始开发工作时印象较深的线程工具类,也是向以前岗位上大牛前辈的代码中学习体会到的。

11、InheritableThreadLocal varlidate = new InheritableThreadLocal(); + 重写initialValue()方法,声明的线程局部变量类,是继承了ThreadLocal类,但扩展了可以将局部变量的值传给子线程使用,但这是继承不是共用,子线程获取后的值改变不会影响传值线程的局部变量值。可以重写childValue(T t)方法来初始化子线程特定的局部变量。

12、ThreadGroup类表示一组线程,线程组可以包含线程对象,也可以包含其他的线程组对象,它是一个树形结构。通过list()方法打印线程组对象的信息,activeCount()方法获取线程组包含的线程数目,enumerate()方法获取线程组包含的线程列表,interrupt()方法为中断,只对非线程池控制器的使用有效,使用ExecutorService框架无效。

继承ThreadGroup的线程组类,可以通过重写uncaughtExceptio
4000
n(Thread t, Throwable e)方法来定义非捕获异常处理器。

13、实现ThreadFactory接口的工厂类,可以修改线程类的创建方式,可以为有资源限制的场景下创建对象的数目,如我们可以限制一个线程类型的对象不多于n个。重写newThread(Runnable r)方法,返回对应的线程实例。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 线程