精华内容
下载资源
问答
  • 该度量基于标准差图像的计算计算,可用于判断哪种去雾方法优于另一种去雾方法,因为它为雾霾图像提供了定量度量。 任何可以评价我的文件的人都会通过电子邮件请求获得​​我的简单除雾代码。
  • visibilitychange 事件, 简单的说就是 document 对象绑定一个方法, 在H5页面 隐藏或者显示 时候触发。 遇到问题(H5, 指是Vue页面) 前景: APP 内嵌 H5 活动页面, 入口在原生, 活动页面有登陆状态...

    经过和APP同时沟通可以确定, 两种情况:

    1. 原生入口–>H5–>返回原生;
      这个情况下,原生会销毁H5的webview这种情况;
    2. 原生入口–>H5–>打开新的原生(如登录);
      这个情况下,webview’会缓存,只能使用相关回调(如登陆后的回调;
    3. 原生入口–>H5–>第三方网站(如支付)
      这个情况下,webview’会缓存

    对于上述1和3的情况, 可以监听路由变化如:beforeRouteEnter进行逻辑处理, 亲测有效;

    • 摘要:

    本文主要描述的是本人在开发过程中遇到的问题, 以及如何利用 visibilitychange 解决的相关记录。

    visibilitychange 事件, 简单的说就是 document 对象绑定的一个方法, 在H5页面 隐藏或者显示 的时候触发。

    • 遇到的问题(H5, 指的是Vue的页面)

    前景: APP 内嵌 H5 活动页面, 入口在原生, 活动页面有登陆状态的判断逻辑, 登陆为 APP 原生登陆, 登陆成功返回该活动页面;----- 流程图如下:

    Created with Raphaël 2.2.0原生入口H5活动页面是否登录?原生登陆页面登陆成功?noyes
    1. 问题: 未登录进入时, 个人积分不展示, 原生登陆成功后返回该页面, 页面数据没有更新,还是未登录状态;经调试发现, 页面所有的钩子函数都不执行;`
    2. 猜测: APP内部打开H5, 然后离开H5跳转回原生页面, 因为(我们)APP 打开H5的webview是不销毁的(webview可以理解为一个容器,APP用来打开H5页面的,我的理解是类似于浏览器的一个窗口); 所以很可能是APP首次进入,就把H5页面包括资源全部缓存下来,下次在进入这个H5的时候,数据就不会更新了,使用的是之前缓存的数据.`
    • 验证

    1. 网上查阅资料得到的一个方法, HTML的head总增加三个meta标签:
      结果: IOS生效, android 不生效, 开始怀疑是不是缓存导致的, 为什么安卓不生效, 因为能力有限, 所以还是不太清楚 原因;
    `后面的注释, 是我自己的理解`
     <meta http-equiv="Pragma" content="no-cache">  <!-- 关闭缓存 -->
     <meta http-equiv="Cache-Control" content="no-cache"> <!-- 关闭缓存 -->
     <meta http-equiv="Expires" content="0"> <!-- 立即过期,也就是重新请求资源 -->
    

    1. 偶然发现 visibilitychange 这个方法, 于是就开始 google, 最终功夫不负有心人;
      结果: 完美解决了我的问题, 在document.hidden === false的时候, 我重新请求数据接口,更新数据就可以了
      理解: 感觉这种情况, 更像是APP把H5页面后台挂起,(或者通俗说是隐藏掉,用户不可见而已), H5页面还是一直存在, 所以页面不会重新加载, 更别说登陆前后数据变化了.
    // Set the name of the hidden property and the change event for visibility
     var hidden, visibilityChange;
     if (typeof document.hidden !== "undefined") {
       // Opera 12.10 and Firefox 18 and later support hidden = "hidden";
       visibilityChange = "visibilitychange";
     } else if (typeof document.msHidden !== "undefined") {
       hidden = "msHidden";
       visibilityChange = "msvisibilitychange";
     } else if (typeof document.webkitHidden !== "undefined") {
       hidden = "webkitHidden";
       visibilityChange = "webkitvisibilitychange";
     }
    
     handleVisibilityChange() {
       if (document.hidden) { // 页面隐藏
         console.log(document.hidden, document.visibilityState)  // true 'hidden'
       } else { // 页面展示
         console.log(document.hidden, document.visibilityState)  // false 'visible'
       }
     }
    
     // Warn if the browser doesn't support addEventListener or the Page Visibility API
     if (typeof document.addEventListener === "undefined" || hidden === undefined) {
       console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
     } else {
       // Handle page visibility change   
       document.addEventListener(visibilityChange, handleVisibilityChange, false);
     }
    
    1. 因为使用的是 webViewJavascriptBridge 和APP协作开发, 所以可以 H5这边注册一个登陆成功的方法, 让APP调用, 然后回调里 执行 更新数据操作就可以了.

    注意****2. 3 两种方式, 虽然可以成功解决问题, 但是(本人)安卓会出现大概 1s 左右的白屏, 目前还没有解决.希望有大佬可以帮忙指点一下.

    本文参考来自: https://www.jianshu.com/p/e905584f8ed2


    • 学习使我快乐
    展开全文
  • 将复杂SAR场景消隐问题分解为两个简单过程:一是对场景三角网格在发射平面上投影点云做2维Delaunay三角网格划分,二是基于射线管分裂方法对新生网格可见性进行判断和拓扑重构。典型飞机目标和草地上T-72坦克消隐...
  • 采用光线投射方法判断太阳与其他物体遮挡关系,解决了z缓冲区方法无法判断视见体外物体的可见性问题,并利用顶点着色器技术对该方法进行优化。结果显示,该法简单,易于实现,绘制效果真实,满足航海模拟器对视景...
  • 封装好处

    千次阅读 2018-07-11 19:49:59
    封装好处 提高了数据安全 别人不能够通过 变量名.属性名 方式来修改某个私有成员属性 操作简单 封装后,多个调用者在使用... 实现过程对调用者是不可见的,调用者只需调用方法即可,不知道具体实现过程...

    封装的好处

    提高了数据的安全性
        别人不能够通过 变量名.属性名 的方式来修改某个私有的成员属性
    操作简单
        封装后,多个调用者在使用的时候,只需调用方法即可,调用者不需要再进行判断
    隐藏了实现
        实现过程对调用者是不可见的,调用者只需调用方法即可,不知道具体实现过程
    展开全文
  • 可见性 在没有同步情况下 编译器 ...有一种简单的方法能避免这些复杂问题 只要有数据在多个线程之间共享 就使用正确同步 失效数据 非线程安全可变整数类 @NotThreadSafe public class MutableInteger { ...

    可见性
    在没有同步的情况下共享变量(不要这么做)

    public class NoVisibility {
        private static boolean ready;
        private static int number;
    
        private static class ReaderThread extends Thread {
            public void run() {
                while (!ready)
                    Thread.yield();
                System.out.println(number);
            }
        }
    
        public static void main(String[] args) {
            new ReaderThread().start();
            number = 42;
            ready = true;
        }
    }
    

    在没有同步的情况下 编译器 处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整 在缺乏足够同步的多线程程序中 要想对内存操作的执行顺序进行判断 几乎无法得出正确的结论

    有一种简单的方法能避免这些复杂的问题 只要有数据在多个线程之间共享 就使用正确的同步

    失效数据
    非线程安全的可变整数类

    @NotThreadSafe
    public class MutableInteger {
        private int value;
    
        public int get() {
            return value;
        }
    
        public void set(int value) {
            this.value = value;
        }
    }
    

    如果某个线程调用了set 那么另一个正在调用get的线程可能会看到更新后的value值 也可能看不到

    线程安全的可变整数类

    @ThreadSafe
    public class SynchronizedInteger {
        @GuardedBy("this") private int value;
    
        public synchronized int get() {
            return value;
        }
    
        public synchronized void set(int value) {
            this.value = value;
        }
    }
    

    仅对set方法进行同步是不够的 调用get的线程仍然会看见失效值 这里的锁是当前对象 调用get或set首先要获得锁

    非原子的64位操作
    当读取一个非volatile类型的long变量时 如果对该变量的读操作和写操作在不同的线程中执行 那么很可能会读取到某个值的高32位和另一个值的低32位

    加锁与可见性
    加锁的含义不仅仅局限于互斥行为 还包括内存可见性 为了确保所有线程都能看到共享变量的最新值 所有执行读操作或者写操作的线程都必须在同一个锁上同步

    Volatile变量
    仅当volatile变量能简化代码的实现以及对同步策略的验证时 才应该使用它们 如果在验证正确性时需要对可见性进行复杂的判断 那么就不要使用volatile变量 volatile变量的正确使用方式包括:确保它们自身状态的可见性 确保它们所引用对象的状态的可见性 以及标识一些重要的程序生命周期事件的发生(例如 初始化或关闭)

    volatile变量的一种典型用法 检查某个状态标记以判断是否退出循环
    数绵羊

    public class CountingSheep {
        volatile boolean asleep;
    
        void tryToSleep() {
            while (!asleep)
                countSomeSheep();
        }
    
        void countSomeSheep() {
            // One, two, three...
        }
    }
    

    加锁机制既可以确保可见性又可以确保原子性 而volatile变量只能确保可见性

    当且仅当满足以下所有条件时 才应该使用volatile变量:

    • 对变量的写入操作不依赖变量的当前值 或者你能确保只有单个线程更新变量的值
    • 该变量不会与其他状态变量一起纳入不变性条件中
    • 在访问变量时不需要加锁

    发布与逸出
    发布(Publish) 一个对象的意思是指 使对象能够在当前作用域之外的代码中使用
    当某个不应该发布的对象被发布时 这种情况就被称为逸出(Escape)

    发布一个对象

    class Secrets {
        public static Set<Secret> knownSecrets;
    
        public void initialize() {
            knownSecrets = new HashSet<Secret>();
        }
    }
    
    
    class Secret {
    }
    

    使内部的可变状态逸出(不要这么做)

    class UnsafeStates {
        private String[] states = new String[]{
            "AK", "AL" /*...*/
        };
    
        public String[] getStates() {
            return states;
        }
    }
    

    隐式地使this引用逸出(不要这么做)

    public class ThisEscape {
        public ThisEscape(EventSource source) {
            source.registerListener(new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            });
        }
    
        void doSomething(Event e) {
        }
    
    
        interface EventSource {
            void registerListener(EventListener e);
        }
    
        interface EventListener {
            void onEvent(Event e);
        }
    
        interface Event {
        }
    }
    
    

    安全的对象构造过程
    不要在构造过程中使this引用逸出

    使用工厂方法来防止this引用在构造过程中逸出

    public class SafeListener {
        private final EventListener listener;
    
        private SafeListener() {
            listener = new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            };
        }
    
        public static SafeListener newInstance(EventSource source) {
            SafeListener safe = new SafeListener();
            source.registerListener(safe.listener);
            return safe;
        }
    
        void doSomething(Event e) {
        }
    
    
        interface EventSource {
            void registerListener(EventListener e);
        }
    
        interface EventListener {
            void onEvent(Event e);
        }
    
        interface Event {
        }
    }
    

    线程封闭
    当访问共享的可变数据时 通常需要使用同步 一种避免使用同步的方式就是不共享数据 如果仅在单线程内访问数据 就不需要同步 这种技术被称为线程封闭(ThreadConfinement) 它是实现线程安全性的最简单方式之一

    Ad-hoc线程封闭
    Ad-hoc线程封闭是指 维护线程封闭性的职责完全由程序实现来承担 Ad-hoc线程封闭是非常脆弱的 因为没有任何一种语言特性 例如可见性修饰符或局部变量 能将对象封闭到目标线程上

    由于Ad-hoc线程封闭技术的脆弱性 因此在程序中尽量少用它 在可能的情况下 应该使用更强的线程封闭技术(例如 栈封闭或ThreadLocal类)

    栈封闭
    栈封闭是线程封闭的一种特例 在栈封闭中 只能通过局部变量才能访问对象

    基本类型的局部变量与引用变量的线程封闭性

    public class Animals {
        Ark ark;
        Species species;
        Gender gender;
    
        public int loadTheArk(Collection<Animal> candidates) {
            SortedSet<Animal> animals;
            int numPairs = 0;
            Animal candidate = null;
    
            // animals confined to method, don't let them escape!
            animals = new TreeSet<Animal>(new SpeciesGenderComparator());
            animals.addAll(candidates);
            for (Animal a : animals) {
                if (candidate == null || !candidate.isPotentialMate(a))
                    candidate = a;
                else {
                    ark.load(new AnimalPair(candidate, a));
                    ++numPairs;
                    candidate = null;
                }
            }
            return numPairs;
        }
    
    
        class Animal {
            Species species;
            Gender gender;
    
            public boolean isPotentialMate(Animal other) {
                return species == other.species && gender != other.gender;
            }
        }
    
        enum Species {
            AARDVARK, BENGAL_TIGER, CARIBOU, DINGO, ELEPHANT, FROG, GNU, HYENA,
            IGUANA, JAGUAR, KIWI, LEOPARD, MASTADON, NEWT, OCTOPUS,
            PIRANHA, QUETZAL, RHINOCEROS, SALAMANDER, THREE_TOED_SLOTH,
            UNICORN, VIPER, WEREWOLF, XANTHUS_HUMMINBIRD, YAK, ZEBRA
        }
    
        enum Gender {
            MALE, FEMALE
        }
    
        class AnimalPair {
            private final Animal one, two;
    
            public AnimalPair(Animal one, Animal two) {
                this.one = one;
                this.two = two;
            }
        }
    
        class SpeciesGenderComparator implements Comparator<Animal> {
            public int compare(Animal one, Animal two) {
                int speciesCompare = one.species.compareTo(two.species);
                return (speciesCompare != 0)
                        ? speciesCompare
                        : one.gender.compareTo(two.gender);
            }
        }
    
        class Ark {
            private final Set<AnimalPair> loadedAnimals = new HashSet<AnimalPair>();
    
            public void load(AnimalPair pair) {
                loadedAnimals.add(pair);
            }
        }
    }
    

    ThreadLocal类
    维持线程封闭性的一种更规范方法是使用ThreadLocal 这个类能使线程中的某个值与保存值的对象关联起来 ThreadLocal提供了get与set等访问接口或方法 这些方法为每个使用该变量的线程都存有一份独立的副本 因此get总是返回由当前执行线程在调用set时设置的最新值

    使用ThreadLocal来维持线程封闭性

    public class ConnectionDispenser {
        static String DB_URL = "jdbc:mysql://localhost/mydatabase";
    
        private ThreadLocal<Connection> connectionHolder
                = new ThreadLocal<Connection>() {
                    public Connection initialValue() {
                        try {
                            return DriverManager.getConnection(DB_URL);
                        } catch (SQLException e) {
                            throw new RuntimeException("Unable to acquire Connection, e");
                        }
                    };
                };
    
        public Connection getConnection() {
            return connectionHolder.get();
        }
    }
    

    不变性
    不可变对象一定是线程安全的

    当满足以下条件时 对象才是不可变的:

    • 对象创建以后其状态就不能修改
    • 对象的所有域都是final类型
    • 对象是正确创建的(在对象的创建期间 this引用没有逸出)

    在可变对象基础上构建的不可变类

    @Immutable
     public final class ThreeStooges {
        private final Set<String> stooges = new HashSet<String>();
    
        public ThreeStooges() {
            stooges.add("Moe");
            stooges.add("Larry");
            stooges.add("Curly");
        }
    
        public boolean isStooge(String name) {
            return stooges.contains(name);
        }
    
        public String getStoogeNames() {
            List<String> stooges = new Vector<String>();
            stooges.add("Moe");
            stooges.add("Larry");
            stooges.add("Curly");
            return stooges.toString();
        }
    }
    

    Final域
    正如 除非需要更高的可见性 否则应将所有的域都声明为私有域是一个良好的编程习惯 除非需要某个域是可变的 否则应将其声明为final域 也是一个良好的编程习惯

    示例:使用Volatile类型来发布不可变对象
    对数值及其因数分解结果进行缓存的不可变容器类

    @Immutable
    public class OneValueCache {
        private final BigInteger lastNumber;
        private final BigInteger[] lastFactors;
    
        public OneValueCache(BigInteger i,
                             BigInteger[] factors) {
            lastNumber = i;
            lastFactors = Arrays.copyOf(factors, factors.length);
        }
    
        public BigInteger[] getFactors(BigInteger i) {
            if (lastNumber == null || !lastNumber.equals(i))
                return null;
            else
                return Arrays.copyOf(lastFactors, lastFactors.length);
        }
    }
    

    使用指向不可变容器对象的volatile类型引用以缓存最新的结果

    @ThreadSafe
    public class VolatileCachedFactorizer extends GenericServlet implements Servlet {
        private volatile OneValueCache cache = new OneValueCache(null, null);
    
        public void service(ServletRequest req, ServletResponse resp) {
            BigInteger i = extractFromRequest(req);
            BigInteger[] factors = cache.getFactors(i);
            if (factors == null) {
                factors = factor(i);
                cache = new OneValueCache(i, factors);
            }
            encodeIntoResponse(resp, factors);
        }
    
        void encodeIntoResponse(ServletResponse resp, BigInteger[] factors) {
        }
    
        BigInteger extractFromRequest(ServletRequest req) {
            return new BigInteger("7");
        }
    
        BigInteger[] factor(BigInteger i) {
            // Doesn't really factor
            return new BigInteger[]{i};
        }
    }
    

    安全发布
    在没有足够同步的情况下发布对象(不要这么做)

    public class StuffIntoPublic {
        public Holder holder;
    
        public void initialize() {
            holder = new Holder(42);
        }
    }
    

    不正确的发布:正确的对象被破坏
    由于未被正确发布 因此这个类可能出现故障

    public class Holder {
        private int n;
    
        public Holder(int n) {
            this.n = n;
        }
    
        public void assertSanity() {
            if (n != n)
                throw new AssertionError("This statement is false.");
        }
    }
    

    不可变对象与初始化安全性
    任何线程都可以在不需要额外同步的情况下安全地访问不可变对象 即使在发布这些对象时没有使用同步

    安全发布的常用模式
    要安全地发布一个对象 对象的引用以及对象的状态必须同时对其他线程可见 一个正确构造的对象可以通过以下方式来安全地发布:

    • 在静态初始化函数中初始化一个对象引用
    • 将对象的引用保存到volatile类型的域或者AtomicReferance对象中
    • 将对象的引用保存到某个正确构造对象的final类型域中
    • 将对象的引用保存到一个由锁保护的域中

    事实不可变对象
    如果对象从技术上来看是可变的 但其状态在发布后不会再改变 那么把这种对象称为 事实不可变对象
    在没有额外的同步的情况下 任何线程都可以安全地使用被安全发布的事实不可变对象

    可变对象
    对于可变对象 不仅在发布对象时需要使用同步 而且在每次对象访问时同样需要使用同步来确保后续修改操作的可见性 要安全地共享可变对象 这些对象就必须被安全地发布 并且必须是线程安全的或者由某个锁保护起来
    对象的发布需求取决于它的可变性:

    • 不可变对象可以通过任意机制来发布
    • 事实不可变对象必须通过安全方式来发布
    • 可变对象必须通过安全方式来发布 并且必须是线程安全的或者由某个锁保护起来

    安全地共享对象
    在并发程序中使用和共享对象时 可以使用一些实用的策略 包括:
    线程封闭 线程封闭的对象只能由一个线程拥有 对象被封闭在该线程中 并且只能由这个线程修改
    只读共享 在没有额外同步的情况下 共享的只读对象可以由多个线程并发访问 但任何线程都不能修改它 共享的只读对象包括不可变对象和事实不可变对象
    线程安全共享 线程安全的对象在其内部实现同步 因此多个线程可以通过对象的公有接口来进行访问而不需要进一步的同步
    保护对象 被保护的对象只能通过持有特定的锁来访问 保护对象包括封装在其他线程安全对象中的对象 以及已发布的并且由某个特定锁保护的对象

    展开全文
  • 线程任务取消

    2011-11-25 09:10:00
    当外部代码能够在活动...最简单的任务取消策略就是在线程中维持一个bool变量,在run方法判断此变量bool值来决 定是否取消任务。显然,这个bool变量需要声明为volatile,以保持多线程环境下可见性(所谓可见性,...
      当外部代码能够在活动自然完成之前,把它的状态更改为完成状态,那么这个活动被称为可取消(cancellable)。取消任务是一个很常见的需求,无论 是由于用户请求还是系统错误引起的服务关闭等等原因。最简单的任务取消策略就是在线程中维持一个bool变量,在run方法中判断此变量的bool值来决 定是否取消任务。显然,这个bool变量需要声明为volatile,以保持多线程环境下可见性(所谓可见性,就是当一个线程修改共享对象的状态变量后,另一个线程 可以马上看到修改的结果)。下面是一个来自《java并发编程实践》的例子:
    java 代码
     
    1. package net.rubyeye.concurrency.chapter7;  
    2.   
    3. import java.math.BigInteger;  
    4. import java.util.ArrayList;  
    5. import java.util.List;  
    6. import java.util.concurrent.TimeUnit;  
    7.   
    8. public class PrimeGenerator implements Runnable {  
    9.     private final List<biginteger> primes = </biginteger>new ArrayList<biginteger>();  </biginteger>
    10.   
    11.     private volatile boolean cancelled;  
    12.     public void run() {  
    13.         BigInteger p = BigInteger.ONE;  
    14.         while (!cancelled) {  
    15.             p = p.nextProbablePrime();  
    16.             synchronized (this) {  
    17.                 primes.add(p);  
    18.             }  
    19.         }  
    20.     }  
    21.     public void cancel() {  
    22.         cancelled = true;  
    23.     }  
    24.     public synchronized List<biginteger> get() {  </biginteger>
    25.         return new ArrayList<biginteger>(primes);  </biginteger>
    26.     }  
    27.   
    28.     public static void main(String args[]) throws InterruptedException {  
    29.         PrimeGenerator generator = new PrimeGenerator();  
    30.         new Thread(generator).start();  
    31.         try {  
    32.             TimeUnit.SECONDS.sleep(1);  
    33.         } finally {  
    34.             generator.cancel();  
    35.         }  
    36.     }  
    37. }  

        main中启动一个素数生成的任务,线程运行一秒就取消掉。通过线程中的cancelled变量来表征任务是否继续执行。既然是最简单的策略,那么什么是 例外情况?显然,阻塞操作下(比如调用join,wait,sleep方法),这样的策略会出问题。任务因为调用这些阻塞方法而被阻塞,它将不会去检查 volatile变量,导致取消操作失效。那么解决办法是什么?中断!考虑我们用BlockingQueue去保存生成的素数, BlockingQueue的put方法是阻塞的(当BlockingQueue满的时候,put操作会阻塞直到有元素被take),让我们看看不采用中 断,仍然采用简单策略会出现什么情况:
    java 代码
     
    1. package net.rubyeye.concurrency.chapter7;  
    2.   
    3. import java.math.BigInteger;  
    4. import java.util.concurrent.BlockingQueue;  
    5. import java.util.concurrent.CountDownLatch;  
    6. import java.util.concurrent.LinkedBlockingQueue;  
    7. import java.util.concurrent.TimeUnit;  
    8.   
    9. public class BrokenPrimeProducer extends Thread {  
    10.     static int i = 1000;  
    11.   
    12.     private final BlockingQueue<biginteger> queue;  </biginteger>
    13.   
    14.     private volatile boolean cancelled = false;  
    15.   
    16.     BrokenPrimeProducer(BlockingQueue<biginteger> queue) {  </biginteger>
    17.         this.queue = queue;  
    18.     }  
    19.   
    20.     public void run() {  
    21.         BigInteger p = BigInteger.ONE;  
    22.         try {  
    23.             while (!cancelled) {  
    24.                 p = p.nextProbablePrime();  
    25.                 queue.put(p);  
    26.             }  
    27.         } catch (InterruptedException cusumed) {  
    28.         }  
    29.     }  
    30.   
    31.     public void cancel() {  
    32.         this.cancelled = false;  
    33.     }  
    34.   
    35.     public static void main(String args[]) throws InterruptedException {  
    36.         BlockingQueue<biginteger> queue = new LinkedBlockingQueue<biginteger>(  </biginteger></biginteger>
    37.                 10);  
    38.         BrokenPrimeProducer producer = new BrokenPrimeProducer(queue);  
    39.         producer.start();  
    40.         try {  
    41.             while (needMorePrimes())  
    42.                 queue.take();  
    43.         } finally {  
    44.             producer.cancel();  
    45.         }  
    46.     }  
    47.   
    48.     public static boolean needMorePrimes() throws InterruptedException {  
    49.         boolean result = true;  
    50.         i--;  
    51.         if (i == 0)  
    52.             result = false;  
    53.         return result;  
    54.     }  
    55. }  
    56.     

      我们在main中通过queue.take来消费产生的素数(虽然仅仅是取出扔掉),我们只消费了1000个素数,然后尝试取消产生素数的任务,很遗憾, 取消不了,因为产生素数的线程产生素数的速度大于我们消费的速度,我们在消费1000后就停止消费了,那么任务将被queue的put方法阻塞,永远也不 会去判断cancelled状态变量,任务取消不了。正确的做法应当是使用中断(interrupt):
    java 代码
     
    1. package net.rubyeye.concurrency.chapter7;  
    2.   
    3. import java.math.BigInteger;  
    4. import java.util.concurrent.BlockingQueue;  
    5. import java.util.concurrent.CountDownLatch;  
    6. import java.util.concurrent.LinkedBlockingQueue;  
    7. import java.util.concurrent.TimeUnit;  
    8.   
    9. public class PrimeProducer extends Thread {  
    10.     static int i = 1000;  
    11.   
    12.     private final BlockingQueue<biginteger> queue;  </biginteger>
    13.   
    14.     private volatile boolean cancelled = false;  
    15.   
    16.     PrimeProducer(BlockingQueue<biginteger> queue) {  </biginteger>
    17.         this.queue = queue;  
    18.     }  
    19.   
    20.     public void run() {  
    21.         BigInteger p = BigInteger.ONE;  
    22.         try {  
    23.             while (!Thread.currentThread().isInterrupted()) {  
    24.                 p = p.nextProbablePrime();  
    25.                 queue.put(p);  
    26.             }  
    27.         } catch (InterruptedException cusumed) {  
    28.         }  
    29.     }  
    30.   
    31.     public void cancel() {  
    32.         interrupt();  
    33.     }  
    34.   
    35.     public static void main(String args[]) throws InterruptedException {  
    36.         BlockingQueue<biginteger> queue = new LinkedBlockingQueue<biginteger>(  </biginteger></biginteger>
    37.                 10);  
    38.         PrimeProducer producer = new PrimeProducer(queue);  
    39.         producer.start();  
    40.         try {  
    41.             while (needMorePrimes())  
    42.                 queue.take();  
    43.         } finally {  
    44.             producer.cancel();  
    45.         }  
    46.     }  
    47.   
    48.     public static boolean needMorePrimes() throws InterruptedException {  
    49.         boolean result = true;  
    50.         i--;  
    51.         if (i == 0)  
    52.             result = false;  
    53.         return result;  
    54.     }  
    55. }  
    56.     

       在run方法中,通过Thread的isInterrupted来判断interrupt status是否已经被修改,从而正确实现了任务的取消。关于interrupt,有一点需要特别说明,调用interrupt并不意味着必然停止目标线 程的正在进行的工作,它仅仅是传递一个请求中断的信号给目标线程,目标线程会在下一个方便的时刻中断。而对于阻塞方法产生的 InterruptedException的处理,两种选择:要么重新抛出让上层代码来处理,要么在catch块中调用Thread的interrupt 来保存中断状态。除非你确定要让工作线程终止(如上所示代码),否则不要仅仅是catch而不做任务处理工作(生吞了 InterruptedException),更详细可以参考这里。如果不清楚外部线程的中断策略,生搬硬套地调用interrupt可能产生不可预料的后果,可参见书中7.1.4例子。

       另外一个取消任务的方法就是采用Future来管理任务,这是JDK5引入的,用于管理任务的生命周期,处理异常等。比如调用ExecutorService的sumit方法会返回一个Future来描述任务,而Future有一个cancel方法用于取消任务。
       那么,如果任务调用了不可中断的阻塞方法,比如Socket的read、write方法,java.nio中的同步I/O,那么该怎么处理呢?简单地,关闭它们!参考下面的例子:
    java 代码
     
    1. package net.rubyeye.concurrency.chapter7;  
    2.   
    3. import java.io.IOException;  
    4. import java.io.InputStream;  
    5. import java.net.Socket;  
    6.   
    7. /** 
    8.  * 展示对于不可中断阻塞的取消任务 通过关闭socket引发异常来中断 
    9.  *  
    10.  * @author Admin 
    11.  *  
    12.  */  
    13. public abstract class ReaderThread extends Thread {  
    14.     private final Socket socket;  
    15.   
    16.     private final InputStream in;  
    17.   
    18.     public ReaderThread(Socket socket) throws IOException {  
    19.         this.socket = socket;  
    20.         this.in = socket.getInputStream();  
    21.     }  
    22.   
    23.     // 重写interrupt方法  
    24.     public void interrupt() {  
    25.         try {  
    26.             socket.close();  
    27.         } catch (IOException e) {  
    28.         } finally {  
    29.             super.interrupt();  
    30.         }  
    31.     }  
    32.   
    33.     public void run() {  
    34.         try {  
    35.             byte[] buf = new byte[1024];  
    36.             while (true) {  
    37.                 int count = in.read(buf);  
    38.                 if (count < 0)  
    39.                     break;  
    40.                 else if (count > 0)  
    41.                     processBuff(buf, count);  
    42.             }  
    43.         } catch (IOException e) {  
    44.         }  
    45.     }  
    46.   
    47.     public abstract void processBuff(byte[] buf, int count);  
    48. }  
    49.     


      Reader线程重写了interrupt方法,其中调用了socket的close方法用于中断read方法,最后,又调用了super.interrupt(),防止当调用可中断的阻塞方法时不能正常中断。

      调用阻塞方法(join,wait,sleep),那么当收到中断信号,会抛出InterruptedException,离开阻塞状态;而如果没有调用 这些阻塞方法,中断信号将可以被忽略,当然你可以通过Thread.currentThread().isInterrupted()判断状态来进行手工 处理。

    转载于:https://www.cnblogs.com/diyunpeng/archive/2011/11/25/2262597.html

    展开全文
  • 获取最新版本扩展程序简单方法是完全关闭google chrome,然后重新打开。 您可以通过在管理扩展上检查版本号并与我们进行比较来判断您是否正在运行最新版本 这是HubSpot官方Chrome扩展程序吗? 没有。 该...
  • 超实用jQuery代码段

    2019-03-04 10:20:41
    超实用jQuery代码段精选近350个jQuery代码段,涵盖页面开发中绝大多数要点、技巧与方法,堪称史上最实用jQuery代码参考书,可以视为网页设计与网站建设人员好帮手。《超实用jQuery代码段》代码跨平台、跨...
  • 11.2.2 类的可见性 293 11.2.3 final——让类不可被继承 295 11.2.4 理解final关键字 296 11.2.5 总结:类修饰符 297 11.3 方法的修饰符 297 11.3.1 方法的访问控制符 298 11.3.2 public:没有限制修饰符 ...
  • 11.2.2 类的可见性 293 11.2.3 final——让类不可被继承 295 11.2.4 理解final关键字 296 11.2.5 总结:类修饰符 297 11.3 方法的修饰符 297 11.3.1 方法的访问控制符 298 11.3.2 public:没有限制修饰符 ...
  • 11.2.2 类的可见性 293 11.2.3 final——让类不可被继承 295 11.2.4 理解final关键字 296 11.2.5 总结:类修饰符 297 11.3 方法的修饰符 297 11.3.1 方法的访问控制符 298 11.3.2 public:没有限制修饰符 ...
  • W3C 万维网联盟,创建于1994年,是Web技术领域最具权威和影响力国际中立技术标准机构。主要工作是发展 Web 规范,这些规范描述了 Web 通信协议(比如 HTML 和 XHTML)和其他构建模块。 NativeApp 使用...
  • /usr/lib之类目录下,c源程序里直接写#include 时,能直接去找到它们,在VC里,同样,最简单的方法就是将oSIP2源码包中Include目录下 osipparser2目录直接拷到我们Windows下默认...
  • 发现测量页面主要内容的可见时间有一种更精准且简单的方法是查看什么时候渲染最大元素。 以上图为例,绿色方块区域是内容最大元素,所以在这个例子中,LCP等于这个元素开始渲染时间。 现在...
  • 设计模式

    2019-07-24 16:53:25
    单例模式需要解决线程安全问题,因此实例本身需要用volatile关键字实现可见性和禁止重排序,再进行双重验证锁(即对获得实例的方法进行同步,同时两次判断实例是否确定为空,只有确定为空才可以创建实例) 更简单的...
  • dreamweaver各种组件

    2008-06-26 16:55:56
    Check Form 利用Check Form您可以真正检查表单填写正确,并且可以自定义报错信息! Animate Images 它可以使用JPG格式也可以用动态形式表现出来,并且您可以定义触发动作,获得最大主动! Add Favourite...
  • pbrt学习笔记1——光线追踪 ...(就是模拟现实中光线运行方式,通过判断光线是否与物体相交来确定确定交点颜色,无数条光线与物体折射或者反射,从而实现整个场景渲染着色)虽然有很多方法来编写光线追
  • 多视点方法也是管理需求变化一种新方法,它可以用于管理不一致, 并进行关于变化推理。 2. M公司软件产品以开发实验型新软件为主。用瀑布模型进行软件开发已经有近十年了,并取得了一些成功。若你作为一...
  • 影响单片机系统运行稳定性的因素可大体分为外因和内因两部分: 外因:即射频干扰,它是以空间电磁场的形式传递在机器内部的导体(引线 或零件引脚)感生出相应的干扰,可通过电磁屏蔽和合理的布线/器件布局衰减 该类...
  • 同时还能更好利用内存局部原理,增加树度可以减少树高度,比如每个树度最大是1000时;这样就形成了一颗m叉平衡查找树。这正是B+树核心,也是众多存储引擎使用数据...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 131
精华内容 52
关键字:

判断可见性的简单方法