博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java并发编程笔记—基础知识—实用案例
阅读量:7068 次
发布时间:2019-06-28

本文共 8058 字,大约阅读时间需要 26 分钟。

如何正确停止一个线程

1)共享变量的使用

中断线程最好的,最受推荐的方式是,使用共享变量(shared variable)发出信号,告诉线程必须停止正在运行的任务。线程必须周期性的核查这一变量(尤其在冗余操作期间),然后有秩序地中止任务。当线程等待某些事件发生而被阻塞,又会发生什么?果线程被阻塞,它便不能核查共享变量,也就不能停止。这在许多情况下会发生,例如调用Object.wait()、ServerSocket.accept()和DatagramSocket.receive()时。
 

2)Thread.interrupt()的理解

Thread.interrupt()方法不会中断一个正在运行的线程。这一方法实际上完成的是,在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。
 

正确的停止线程方式是设置共享变量,并调用interrupt()(注意变量应该先设置)。如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就将得到异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。在任何一种情况中,最后线程都将检查共享变量然后再停止。 

实例如下:

package com.iflytek.ossp.bliserver.common.utils;public abstract class MyWorkRunnable implements Runnable {    volatile Thread mTheThread = null;    @Override    public void run() {        if (mTheThread != Thread.currentThread()) {            throw new RuntimeException();        }        while (!Thread.interrupted() && mTheThread != null) {            execute();            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();                mTheThread.interrupt();            }        }    }    public void start() {        mTheThread = new Thread(this);        mTheThread.start();    }    public void stop() {        if (mTheThread != null) {            mTheThread.interrupt();            try {                mTheThread.join(); // 等待线程彻底结束            } catch (InterruptedException e) {                e.printStackTrace();                mTheThread.interrupt();            }        }    }    public abstract void execute();}

  

在现有的线程安全类中添加功能

假设有一个线性的链表,需要提供一个原子的“若没有则添加”的操作。

第一种方法:扩展现有的类

public class BetterVector
extends Vector
{ public synchronized boolean putIfAbsent(E x) { boolean absent = !contains(x); if (absent) add(x); return absent; }}

第二种方法:客户端加锁

注意下面这张方法是不能实现线程安全的。

public class ListHelper
{ public List
list = Collections.synchronizedList(new ArrayList
()); public synchronized boolean putIfAbsent(E x) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; }}

问题出在使用错误的锁进行同步,无论List使用哪一个锁来保护它的状态,可以确定的是这个锁并不是ListHelper上的锁。

正确的方式是是使用客户端加锁:

public class ListHelper
{ public List
list = Collections.synchronizedList(new ArrayList
()); public boolean putIfAbsent(E x) { synchronized (list) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } }}

但这张方法是脆弱的,因为需要依赖List的加锁策略,只有在遵循加锁策略上的类使用客户端加锁才有效。

最好的方式是使用组合:

public class ImprovedList
implements List
{ private final List
list; public ImprovedList(List
list) { this.list = list; } public synchronized boolean putIfAbsent(T x) { boolean contains = !list.contains(x); if (contains) list.add(x); return contains; } public synchronized void clear() { list.clear(); } // ......按照类似的方式委托list的其他方法。}

  

ThreadLocal的使用

下面是一个使用ThreadLocal来记录线程中各个方位调用耗时的帮助类。

import java.util.Date;import java.util.HashMap;import java.util.Map;/** * 用于跟踪各个线程中方法调用的耗时等信息。 * 

* 对于一个线程串行多次执行同一个方法,只能跟踪到最后一次的执行信息。 * * @author jdzhan,2013-1-13 * */public final class MethodCallTrace { private static final ThreadLocal

> mutilThreadTraces = new ThreadLocal
>() { @Override protected Map
initialValue() { return new HashMap
(); } }; /** * 开始跟踪 */ public static void start() { String funcName = new Throwable().getStackTrace()[1].getMethodName(); start(funcName); } /** * 结束跟踪 */ public static void end() { String funcName = new Throwable().getStackTrace()[1].getMethodName(); end(funcName); } /** * 开始跟踪 * * @param funcName * 指定一个方法名称 */ public static void start(String funcName) { TraceInfo item = new TraceInfo(); item.setStartTime(new Date()); Map
traces = null; if (mutilThreadTraces.get() == null) { traces = new HashMap
(); mutilThreadTraces.set(traces); } else { traces = mutilThreadTraces.get(); } traces.put(funcName, item); } /** * 结束跟踪 * * @param funcName * 指定一个方法名 */ public static void end(String funcName) { Map
traces = mutilThreadTraces.get(); if (traces == null) { return; } TraceInfo item = traces.get(funcName); if (item == null) { return; } item.setEndTime(new Date()); } public static Map
getTrace() { return mutilThreadTraces.get(); }}

MethodCallTrace
import java.util.Date;public class TraceInfo {    private Date startTime;    private Date endTime;    public Date getStartTime() {        return new Date(startTime.getTime());    }    public void setStartTime(Date startTime) {        this.startTime = new Date(startTime.getTime());    }    public Date getEndTime() {        return new Date(endTime.getTime());    }    public void setEndTime(Date endTime) {        this.endTime = new Date(endTime.getTime());    }    /**     * 获取方法调用的耗时,如果返回-1或小于0说明记录存在问题。     *      * @return     */    public long getCallTime() {        if (startTime == null || endTime == null) {            return -1;        }        return endTime.getTime() - startTime.getTime();    }}
TraceInfo
import java.util.Map;import java.util.Map.Entry;public class ThreadLocalTest {    /**     * @param args     */    public static void main(String[] args) {        MethodCallTrace.start();        for (int i = 0; i < 3; i++) {            new Thread(new Runnable() {                @Override                public void run() {                    test();                    test2();                    test3();                    Map
trace = MethodCallTrace.getTrace(); for (Entry
entry : trace.entrySet()) { System.out.println(Thread.currentThread().getId() + entry.getKey() + ":" + entry.getValue().getCallTime() + "毫秒"); } } }).start(); } while (true) { try { Thread.sleep(3000); MethodCallTrace.end(); Map
trace = MethodCallTrace.getTrace(); for (Entry
entry : trace.entrySet()) { System.out.println("主线程:" + entry.getKey() + ":" + entry.getValue().getCallTime() + "毫秒"); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private static void test() { MethodCallTrace.start(); for (int i = 0; i < 1; i++) { try { Thread.sleep(Thread.currentThread().getId()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } MethodCallTrace.end(); } private static void test2() { MethodCallTrace.start("test2"); for (int i = 0; i < 10; i++) { try { Thread.sleep(Thread.currentThread().getId()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } MethodCallTrace.end("test2"); } private static void test3() { MethodCallTrace.start("test3"); for (int i = 0; i < 10; i++) { try { Thread.sleep(Thread.currentThread().getId()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } MethodCallTrace.end("test3"); }}
待补充……
 
 

转载于:https://www.cnblogs.com/zhanjindong/p/3515234.html

你可能感兴趣的文章
polysh入门
查看>>
mavn打jar包
查看>>
spring @Transactional注解参数详解
查看>>
RDD到底是什么东西(一)
查看>>
Scala类型参数
查看>>
redis缓存java项目中,配置和使用
查看>>
Linux中Mysql主从配置
查看>>
mongodb将副本集转换为切片集群
查看>>
JimStoneAjax使用ANT或者Maven等自动部署工具编译时需要添加debug参数
查看>>
【自用】 Python 信息熵 信息增益
查看>>
Java中BigDecimal的应用
查看>>
DataGrid的itemreader中使用outerDocument
查看>>
理解 JavaScript 的函数
查看>>
面试题之总结-大数运算
查看>>
我们为什么要使用NOSQL非关系数据库?
查看>>
【转载】QPS、PV 、RT(响应时间)之间的关系
查看>>
PHPdom操作查找xml标签文本
查看>>
git多个公钥
查看>>
java基础
查看>>
idea在window10 快捷键的坑
查看>>