精华内容
下载资源
问答
  • Java停止一个线程有三种办法: 1.正常结束执行; 2.发生异常; 3.被其他线程stop(Java官方不建议) 参考:...

    在Java中停止一个线程有三种办法 :

    1.正常结束执行;

    2.发生异常;

    3.被其他线程stop(Java官方不建议)

    参考:https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

    为什么Thread.stop弃用?

    因为它本质上是不安全的。停止线程会导致它解锁已锁定的所有监视器。(当ThreadDeath异常传播到堆栈中时,监视器将被解锁。)如果先前受这些监视器保护的任何对象处于不一致状态,则其他线程现在可以以不一致的状态查看这些对象。据说这些物体已被 损坏。当线程对受损对象进行操作时,可能会导致任意行为。这种行为可能很微妙并且难以检测,或者可能是明显的。与其他未经检查的异常不同,它会 ThreadDeath默默地杀死线程; 因此,用户没有警告他的程序可能被破坏。

     

    所以如果遇到一种特殊情况某一个线程A会一直执行下去停不下来,这种情况是存在的比如那种需要持续取样的线程A,当然了在正常代码里会有“停止”功能,外部线程B可以发送停止信号给A,A可以直接结束。

    如果A线程没有这种信号量那么B线程还可以主动停止他么?答案是不可以!

    public class Test {
    
        public static void main(String args[]) throws InterruptedException {
    
            Thread thread1 = new Thread() {
                public void run() {
                    fun_a();
                }
            };
            thread1.start();
    
            int a = 0;
            while (a < 100) {
                Thread.sleep(1000);
                a++;
                if (a == 3) {
                    a = 100;
                    thread1.interrupt();
                    //thread1.stop();
                    //throw new RuntimeException("主函数抛出异常");
                }
            }
        }
    
        public static void fun_a() {
            for (; ; ) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(">> " + DateUtil.getNowTimeString());
            }
        }
    }
    

     可以看到interrupt并不能让运行中的线程停止,这个是很容易被误解的地方。这个方法的作用并不是中断线程,而是设置一个标识,通知该线程可以被中断了,到底是继续执行,还是中断返回,由线程本身自己决定。

    当对一个线程调用了interrupt()之后,如果该线程处于被阻塞状态(比如执行了wait、sleep或join等方法),那么会立即退出阻塞状态,并抛出一个InterruptedException异常,在代码中catch这个异常进行后续处理。如果线程一直处于运行状态,那么只会把该线程的中断标志设置为 true,仅此而已,所以interrupt()并不能真正的中断线程,不过在rpc调用的场景中,请求线程一般都处于阻塞状态,等待数据返回,这时interrupt()方法是可以派上用场的。

    参考:Java中如何实现线程的超时中断

     

    修改子线程的代码:

    public static void fun_a() {
            for (; ; ) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException("子线程抛出异常");
                    //e.printStackTrace();
                }
                System.out.println(">> " + DateUtil.getNowTimeString());
            }
        }

    这次是可以结束子线程,前提是子线程自己有异常捕获机制,可以接受其他线程发来的InterruptedException:

     

    主线程每隔2秒对子线程进行一次Interrupted:

    package com.t.www;
    
    public class Test {
        final static Object lock = new Object();
        volatile boolean stop = false;
    
        public static void main(String args[]) throws InterruptedException {
    
            Thread thread1 = new Thread() {
                public void run() {
                    fun_a();
                }
            };
            thread1.start();
            System.out.println("> 1 主线程start " + DateUtil.getNowTimeString());
            int a = 0;
            while (a < 3) {
                Thread.sleep(2000);
                a++;
                System.out.println("> 2 主线程对子线程开始interrupt " + DateUtil.getNowTimeString());
                thread1.interrupt();
                System.out.println("> 3 主线程对子线程完成interrupt " + DateUtil.getNowTimeString());
            }
        }
    
        public static void fun_a() {
            for (; ; ) {
                try {
                    System.out.println(">> 1 子线程wait " + DateUtil.getNowTimeString());
                    synchronized (lock) {
                        lock.wait();
                    }
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //throw new RuntimeException("子线程抛出异常");
                    e.printStackTrace();
                }
                System.out.println(">> 2 子线程完成 " + DateUtil.getNowTimeString());
            }
        }
    }
    

     

     修改子线程代码:

    try {
                    System.out.println(">> 1 子线程wait " + DateUtil.getNowTimeString());
                    synchronized (lock) {
                        lock.wait();
                    }
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //throw new RuntimeException("子线程抛出异常");
                    //e.printStackTrace();
                    System.out.println(">> 2 子线程捕获异常 " + DateUtil.getNowTimeString());
                }

    从运行结果看和前面一致,只是没有抛出异常。 

     

    修改代码子线程使用while(!Thread.currentThread().isInterrupted())判断:

    public class Test {
    
        public static void main(String args[]) throws InterruptedException {
    
            Thread thread1 = new Thread() {
                public void run() {
                    fun_a();
                }
            };
            thread1.start();
            System.out.println("> 1 主线程start " + DateUtil.getNowTimeString());
            int a = 0;
            while (a < 3) {
                Thread.sleep(2000);
                a++;
                System.out.println("> 2 主线程对子线程开始interrupt " + DateUtil.getNowTimeString());
                thread1.interrupt();
                System.out.println("> 3 主线程对子线程完成interrupt " + DateUtil.getNowTimeString());
            }
        }
    
        public static void fun_a() {
            while(!Thread.currentThread().isInterrupted()){
                try {
    
                    System.out.println(">> 1 子线程 " + DateUtil.getNowTimeString());
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //throw new RuntimeException("子线程抛出异常");
                    //e.printStackTrace();
                    System.out.println(">> 2 子线程捕获异常 " + DateUtil.getNowTimeString());
                }
                System.out.println(">> 3 子线程完成 " + DateUtil.getNowTimeString());
            }
            System.out.println(">> 4 子线程正常结束 " + DateUtil.getNowTimeString());
        }
    }
    

    可以看到这次因为子线程增加了状态判断所以可以正常结束: 

    比较优雅的方式是使用一个变量在线程间通信,需要注意的是要保证可见性:

    public class Test {
        private static volatile boolean finished = false;   // ① volatile条件变量
        public static void main(String args[]) throws InterruptedException {
    
            Thread thread1 = new Thread() {
                public void run() {
                    fun_a();
                }
            };
            thread1.start();
            System.out.println("> 1 主线程start " + DateUtil.getNowTimeString());
            int a = 0;
            while (a < 3) {
                Thread.sleep(2000);
                a++;
            }
            System.out.println("> 1 主线程 a=" +a+" "+ DateUtil.getNowTimeString());
            finished=true;
        }
    
        public static void fun_a() {
            while(!finished){
                try {
    
                    System.out.println(">> 1 子线程 " + DateUtil.getNowTimeString());
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //throw new RuntimeException("子线程抛出异常");
                    //e.printStackTrace();
                    System.out.println(">> 2 子线程捕获异常 " + DateUtil.getNowTimeString());
                }
                System.out.println(">> 3 子线程完成 " + DateUtil.getNowTimeString());
            }
            System.out.println(">> 4 子线程正常结束 " + DateUtil.getNowTimeString());
        }
    }
    

    ------------------

    如何停止线程或任务

     

    如何停止一个正在运行的java线程

    了解Java中的线程中断

    如何在Java中正确停止Thread?

    你如何杀死Java中的线程?

    如何在运行时停止/终止长时间运行的Java线程?超时 - >取消 - >中断状态

    Java - 从不同的类停止线程

    https://javaconceptoftheday.com/how-to-stop-a-thread-in-java/

    如何超时一个线程

     

    参考《Effective Java 中文版 第3版

    展开全文
  • VC 打开关闭一个线程

    2015-01-05 17:07:31
    VC正确打开关闭一个线程,运用信号量,以前喜欢运用BOOL全局变量关闭,但老有Bug。
  • JAVA如何在一个线程里面停掉另一个线程,是在一个线程里面哦 PS:新人第一次问问题,希望大神求教
  •  java线程的中断(interrupt)只是改变了线程的中断状态,至于这中断状态改变后带来的结果,那是无法确定的,有时它更是让停止线程继续执行的唯一手段。不但不是让线程停止运行,反而是继续执行线程的...
  • 如何优雅地停止一个线程

    千次阅读 2019-09-03 09:11:57
    Java Thread 类有一个 stop() 方法,可以终止线程,不过这个方法会让线程直接终止,执行的任务立即终止,未执行的任务无法反馈,所以 stop() 方法已经不建议使用。 既然 stop() 方法如此粗暴,不建议使用,...

    线程终止有两种情况:

    1、线程的任务执行完成

    2、线程在执行任务过程中发生异常

     

    这两者属于线程自行终止,如何让线程 A 把线程 B 终止呢?

    Java 中 Thread 类有一个 stop() 方法,可以终止线程,不过这个方法会让线程直接终止,在执行的任务立即终止,未执行的任务无法反馈,所以 stop() 方法已经不建议使用。

     

    既然 stop() 方法如此粗暴,不建议使用,我们如何优雅地结束线程呢?

    线程只有从 runnable 状态(可运行/运行状态) 才能进入terminated 状态(终止状态),如果线程处于 blocked、waiting、timed_waiting 状态(休眠状态),就需要通过 Thread 类的 interrupt()  方法,让线程从休眠状态进入 runnable 状态,从而结束线程。

     

    当线程进入 runnable 状态之后,通过设置一个标识位,线程在合适的时机,检查该标识位,发现符合终止条件,自动退出 run () 方法,线程终止。

     

    如我们模拟一个系统监控任务线程,代码如下

    package constxiong.concurrency.a007;
    
    /**
     * 模拟系统监控
     * @author ConstXiong
     */
    public class TestSystemMonitor {
    	
    	public static void main(String[] args) {
    		testSystemMonitor();//测试系统监控器
    	}
    	
    	/**
    	 * 测试系统监控器
    	 */
    	public static void testSystemMonitor() {
    		SystemMonitor sm = new SystemMonitor();
    		sm.start();
    		try {
    			//运行 10 秒后停止监控
    			Thread.sleep(10 * 1000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("监控任务启动 10 秒后,停止...");
    		sm.stop();
    	}
    	
    }
    
    /**
     * 系统监控器
     * @author ConstXiong
     */
    class SystemMonitor {
    	
    	private Thread t;
    	
    	/**
    	 * 启动一个线程监控系统
    	 */
    	void start() {
    		t = new Thread(() -> {
    			while (!Thread.currentThread().isInterrupted()) {//判断当前线程是否被打断
    				System.out.println("正在监控系统...");
    				try {
    					Thread.sleep(3 * 1000L);//执行 3 秒
    					System.out.println("任务执行 3 秒");
    					System.out.println("监控的系统正常!");
    				} catch (InterruptedException e) {
    					System.out.println("任务执行被中断...");
    				}
    			}
    		});
    		t.start();
    	}
    
    	void stop() {
    		t.interrupt();
    	}
    }
    

    执行结果 

    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    监控任务启动 10 秒后,停止...
    任务执行被中断...
    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    .
    .
    .

     

    从代码和执行结果我们可以看出,系统监控器 start() 方法会创建一个线程执行监控系统的任务,每个任务查询系统情况需要 3 秒钟,在监控 10 秒钟后,主线程向监控器发出停止指令。

    但是结果却不是我们期待的,10 秒后并没有终止了监控器,任务还在执行

     

    原因在于,t.interrupt() 方法让处在休眠状态的语句 Thread.sleep(3 * 1000L); 抛出异常,同时被捕获,此时 JVM 的异常处理会清除线程的中断状态,导致任务一直在执行。

     

    处理办法是,在捕获异常后,继续重新设置中断状态,代码如下

    package constxiong.concurrency.a007;
    
    /**
     * 模拟系统监控
     * @author ConstXiong
     */
    public class TestSystemMonitor {
    	
    	public static void main(String[] args) {
    		testSystemMonitor();//测试系统监控器
    	}
    	
    	/**
    	 * 测试系统监控器
    	 */
    	public static void testSystemMonitor() {
    		SystemMonitor sm = new SystemMonitor();
    		sm.start();
    		try {
    			//运行 10 秒后停止监控
    			Thread.sleep(10 * 1000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("监控任务启动 10 秒后,停止...");
    		sm.stop();
    	}
    	
    }
    
    /**
     * 系统监控器
     * @author ConstXiong
     */
    class SystemMonitor {
    	
    	private Thread t;
    	
    	/**
    	 * 启动一个线程监控系统
    	 */
    	void start() {
    		t = new Thread(() -> {
    			while (!Thread.currentThread().isInterrupted()) {//判断当前线程是否被打断
    				System.out.println("正在监控系统...");
    				try {
    					Thread.sleep(3 * 1000L);//执行 3 秒
    					System.out.println("任务执行 3 秒");
    					System.out.println("监控的系统正常!");
    				} catch (InterruptedException e) {
    					System.out.println("任务执行被中断...");
    					Thread.currentThread().interrupt();//重新设置线程为中断状态
    				}
    			}
    		});
    		t.start();
    	}
    
    	void stop() {
    		t.interrupt();
    	}
    }
    

    执行结果如预期

    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    监控任务启动 10 秒后,停止...
    任务执行被中断...
    

     

    到这里还没有结束,我们用 Thread.sleep(3 * 1000L); 去模拟任务的执行,在实际情况中,一般是调用其他服务的代码,如果出现其他异常情况没有成功设置线程的中断状态,线程将一直执行下去,显然风险很高。所以,需要用一个线程终止的标识来代替 Thread.currentThread().isInterrupted()。

    修改代码如下

    package constxiong.concurrency.a007;
    
    /**
     * 模拟系统监控
     * @author ConstXiong
     */
    public class TestSystemMonitor {
    	
    	public static void main(String[] args) {
    		testSystemMonitor();//测试系统监控器
    	}
    	
    	/**
    	 * 测试系统监控器
    	 */
    	public static void testSystemMonitor() {
    		SystemMonitor sm = new SystemMonitor();
    		sm.start();
    		try {
    			//运行 10 秒后停止监控
    			Thread.sleep(10 * 1000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("监控任务启动 10 秒后,停止...");
    		sm.stop();
    	}
    	
    }
    
    /**
     * 系统监控器
     * @author ConstXiong
     */
    class SystemMonitor {
    	
    	private Thread t;
    	
    	private boolean stop = false;
    	
    	/**
    	 * 启动一个线程监控系统
    	 */
    	void start() {
    		t = new Thread(() -> {
    			while (!stop) {//判断当前线程是否被打断
    				System.out.println("正在监控系统...");
    				try {
    					Thread.sleep(3 * 1000L);//执行 3 秒
    					System.out.println("任务执行 3 秒");
    					System.out.println("监控的系统正常!");
    				} catch (InterruptedException e) {
    					System.out.println("任务执行被中断...");
    					Thread.currentThread().interrupt();//重新设置线程为中断状态
    				}
    			}
    		});
    		t.start();
    	}
    
    	void stop() {
    		stop = true;
    		t.interrupt();
    	}
    }
    

    执行结果

    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    任务执行 3 秒
    监控的系统正常!
    正在监控系统...
    监控任务启动 10 秒后,停止...
    任务执行被中断...
    

    到这里基本算是优雅地让线程终止了。

     

    使用 volatile 修饰 stop 变量有必要吗?作用是什么?

    线程只能通过 runnable 状态到 terminated 状态,那线程状态是如何变化的呢?

    我们后续继续实践。

     


    【Java面试题与答案】整理推荐

     

    展开全文
  • 因为界面相当于开了一个线程我们默认为线程A,计时器倒计时的线程线程B 线程A负责监听界面的事件,以此来决定线程B的执行和终止 方案一:线程A监听到事件直接调用线程B,此时线程A会挂起,整个界面需要等线程B...
  • java 多个线程同时写同一个文件

    千次阅读 2019-10-11 17:00:17
    每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后闭锁上等待的线程就可以恢复工作了。 2.源码 countDownLatch类只提供了一个构造器: //参数count为计数值 public ...

    话不多说,先直接上代码:

    主方法:

    import java.util.concurrent.CountDownLatch;
    
    /**
     * @ProjectName: emp_customer
     * @Package: PACKAGE_NAME
     * @ClassName: Test
     * @Author: Administrator
     * @Description: ${description}
     * @Date: 2019/10/11 14:10
     * @Version: 1.0
     */
    public class Test {
         public static void main(String args[]){
    
             //线程数
             int threadSize=4;
             //源文件地址
             String sourcePath = "E:\\1\\4.txt";
             //目标文件地址
             String destnationPath = "E:\\2\\4.txt";
             //
             CountDownLatch latch = new CountDownLatch(threadSize);
             MultiDownloadFileThread m = new MultiDownloadFileThread(threadSize, sourcePath, destnationPath, latch);
             long startTime = System.currentTimeMillis();
             try {
                 m.excute();
                 latch.await();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             long endTime = System.currentTimeMillis();
             System.out.println("全部下载结束,共耗时" + (endTime - startTime) / 1000 + "s");
         }
    
    }
    

     

    线程类:

    import java.io.*;
    import java.nio.channels.FileChannel;
    import java.nio.channels.FileLock;
    import java.util.concurrent.CountDownLatch;
    
    /**
     * @ProjectName: emp_customer
     * @Package: PACKAGE_NAME
     * @ClassName: MultiDownloadFileThread
     * @Author: Administrator
     * @Description: ${description}
     * @Date: 2019/10/11 15:03
     * @Version: 1.0
     */
    public class MultiDownloadFileThread {
    
        private int threadCount;
        private String sourcePath;
        private String targetPath;
        private CountDownLatch latch;
    
        public MultiDownloadFileThread(int threadCount, String sourcePath, String targetPath, CountDownLatch latch) {
            this.threadCount = threadCount;
            this.sourcePath = sourcePath;
            this.targetPath = targetPath;
            this.latch = latch;
        }
    
        public void excute() {
            File file = new File(sourcePath);
            int fileLength = (int) file.length();
            //分割文件
            int blockSize = fileLength / threadCount;
            for (int i = 1; i <= threadCount; i++) {
                //第一个线程下载的开始位置
                int startIndex = (i - 1) * blockSize;
                int endIndex = startIndex + blockSize - 1;
                if (i == threadCount) {
                    //最后一个线程下载的长度稍微长一点
                    endIndex = fileLength;
                }
                System.out.println("线程" + i + "下载:" + startIndex + "字节~" + endIndex + "字节");
                new DownLoadThread(i, startIndex, endIndex).start();
            }
        }
    
    
        public class DownLoadThread extends Thread {
            private int i;
            private int startIndex;
            private int endIndex;
    
            public DownLoadThread(int i, int startIndex, int endIndex) {
                this.i = i;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
            }
    
            @Override
            public void run() {
                File file = new File(sourcePath);
                FileInputStream in = null;
                RandomAccessFile raFile = null;
                FileChannel fcin = null;
                FileLock flin = null;
                try {
                    in = new FileInputStream(file);
                    in.skip(startIndex);
                    //给要写的文件加锁
                    raFile = new RandomAccessFile(targetPath, "rwd");
                    fcin =raFile.getChannel();
                    while(true){
                        try {
                            flin = fcin.tryLock();
                            break;
                        } catch (Exception e) {
                            System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒,当前进入的线程为:"+i);
                            sleep(1000);
                        }
                    }
                    //随机写文件的时候从哪个位置开始写
                    raFile.seek(startIndex);
                    int len = 0;
                    byte[] arr = new byte[1024];
                    //获取文件片段长度
                    int segLength = endIndex - startIndex + 1;
                    while ((len = in.read(arr)) != -1) {
                        if (segLength > len) {
                            segLength = segLength - len;
                            raFile.write(arr, 0, len);
                        } else {
                            raFile.write(arr, 0, segLength);
                            break;
                        }
                    }
                    System.out.println("线程" + i + "下载完毕");
                    //计数值减一
                    latch.countDown();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (in != null) {
                            in.close();
                        }
                        if (raFile != null) {
                            raFile.close();
                        }
    
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    运行结果:

     

    涉及到的相关知识点:

    1.CountDownLatch 

    2.RandomAccessFile

    3.FileLock

    下面我们具体讲解下

    一、FileLock :文件锁

    FileLock是java 1.4 版本后出现的一个类,它可以通过对一个可写文件(w)加锁,保证同时只有一个进程可以拿到文件的锁,这个进程从而可以对文件做访问;而其它拿不到锁的进程要么选择被挂起等待,要么选择去做一些其它的事情, 这样的机制保证了众进程可以顺序访问该文件。

    1. 概念

    • 共享锁: 共享读操作,但只能一个写(读可以同时,但写不能)。共享锁防止其他正在运行的程序获得重复的独占锁,但是允许他们获得重复的共享锁。
    • 独占锁: 只有一个读或一个写(读和写都不能同时)。独占锁防止其他程序获得任何类型的锁。

    2. lock()和tryLock()的区别:

    lock()阻塞的方法,锁定范围可以随着文件的增大而增加。无参lock()默认为独占锁;有参lock(0L, Long.MAX_VALUE, true)为共享锁。
    tryLock()非阻塞,当未获得锁时,返回null.
    3. FileLock的生命周期:在调用FileLock.release(),或者Channel.close(),或者JVM关闭

    4. FileLock是线程安全的
     

    二、RandomAccessFile

    java除了File类之外,还提供了专门处理文件的类,即RandomAccessFile(随机访问文件)类。该类是Java语言中功能最为丰富的文件访问类,它提供了众多的文件访问方法。RandomAccessFile类支持“随机访问”方式,这里“随机”是指可以跳转到文件的任意位置处读写数据。在访问一个文件的时候,不必把文件从头读到尾,而是希望像访问一个数据库一样“随心所欲”地访问一个文件的某个部分,这时使用RandomAccessFile类就是最佳选择。

    RandomAccessFile对象类有个位置指示器,指向当前读写处的位置,当前读写n个字节后,文件指示器将指向这n个字节后面的下一个字节处。刚打开文件时,文件指示器指向文件的开头处,可以移动文件指示器到新的位置,随后的读写操作将从新的位置开始。RandomAccessFile类在数据等长记录格式文件的随机(相对顺序而言)读取时有很大的优势,但该类仅限于操作文件,不能访问其他的I/O设备,如网络、内存映像等。RandomAccessFile类的构造方法如下所示:

    RandomAccessFile(File file ,  String mode)
    //创建随机存储文件流,文件属性由参数File对象指定

    RandomAccessFile(String name ,  String mode)
    //创建随机存储文件流,文件名由参数name指定

    这两个构造方法均涉及到一个String类型的参数mode,它决定随机存储文件流的操作模式,其中mode值及对应的含义如下:

    “r”:以只读的方式打开,调用该对象的任何write(写)方法都会导致IOException异常
    “rw”:以读、写方式打开,支持文件的读取或写入。若文件不存在,则创建之。
    “rws”:以读、写方式打开,与“rw”不同的是,还要对文件内容的每次更新都同步更新到潜在的存储设备中去。这里的“s”表示synchronous(同步)的意思
    “rwd”:以读、写方式打开,与“rw”不同的是,还要对文件内容的每次更新都同步更新到潜在的存储设备中去。使用“rwd”模式仅要求将文件的内容更新到存储设备中,而使用“rws”模式除了更新文件的内容,还要更新文件的元数据(metadata),因此至少要求1次低级别的I/O操作

     

    三、CountDownLatch

    1.概念

    • countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
    • 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

    2.源码

    • countDownLatch类中只提供了一个构造器:
    //参数count为计数值
    public CountDownLatch(int count) {  };  
    
    • 类中有三个方法是最重要的:
    //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
    public void await() throws InterruptedException { };   
    //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
    //将count值减1
    public void countDown() { };  

    假如在我们的代码里面,我们把main方法里面的

    latch.await();

    注释掉

    如下所示:

    我们可以看到跟之前的输出结果相比,我们的主方法里面输出的:全部下载结束的输出信息,已经打印到我们执行文件下载的线程输出信息的前面了,说明主线程先执行完。这从而说明,await() 方法具有阻塞作用

     我们在把latch.await();放开,把文件下载线程里的latch.countDown();注释掉,

    如下:

    我们可以看到,主程序里的的输出;全部下载结束的输出信息,一直未输出,程序也一直未结束,由此可得,countDown() 方法具有唤醒阻塞线程的作用。

    那么如何让 CountdownLatch 尽早结束

    假如我们的程序执行到countDown()之前就抛出异常,这就可能导致一整情况,CountdownLatch 计数永远不会达到零并且 await() 永远不会终止。

    为了解决这个问题,我们在调用 await() 时添加一个超时参数。

     

    CountDownLatch总结:

        1、CountDownLatch end = new CountDownLatch(N); //构造对象时候 需要传入参数N

      2、end.await()  能够阻塞线程 直到调用N次end.countDown() 方法才释放线程,最好设置超时参数

      3、end.countDown() 可以在多个线程中调用  计算调用次数是所有线程调用次数的总和

     

    对于,本demo而言,加不加文件锁的意义不大,因为在进入线程写的时候,就已经告诉单个线程需要写的内容是哪一块到哪一块,不加锁,也会正常写入,切经本人测试无误,但若是对同一个文件,即要写,又要读话,就必须加锁,不然程序执行可能不完整,具体情况可以查看下面的这个博客:https://blog.csdn.net/gxy3509394/article/details/7435993

    展开全文
  • 一个线程结束时异步通知线程,被通知的线程不用等待!
  • 结束一个线程,听起来好容易,但是结束程序必须按次序进行,以避免发生 race conditions。让程序依次序进行是非常重要的,特别是程序要结束之前。结束一个程序就好像拆除一栋建筑物一样,你以推土机轧平它之前...

    《Win32多线程程序设计》–Jim Beveridge & Robert Wiener

    1. 对于多线程程序,如果用户企图结束程序(主线程)时,子线程尚未完成工作,怎么办?
    2. 结束一个线程,听起来好容易,但是结束程序必须按次序进行,以避免发生 race conditions。让程序依次序进行是非常重要的,特别是在程序要结束之前。结束一个程序就好像拆除一栋建筑物一样,在你以推土机轧平它之前,你必须确定每一个人都安全离开了屋子。结束一个程序也是这样,每一个线程都被迫结束,不管它进行到哪里。

    做法一:在任何子线程还没完成其工作之前,不准用户结束程序(可能需要长时间等待)

    缺点:对于GUI程序,可能需要很长的时间等待程序退出,那么程序有可能看起来像是“挂”了一样。

    做法二:TerminateThread() 放弃一个线程(微软不建议使用)

    缺点:
    TerminateThread() 强迫其行动目标(一个线程)结束,手段激烈而有力,甚至不允许该线程有任何“挣扎”的机会。
    此函数唯一可以预期并依恃的是:线程 handle 将变成激发状态,并且传回dwExitCode 所指定的结束代码。
    副作用:
    1.如果目标线程持有着一个临界区(critical section),这临界区将不会被释放。
    2.如果目标线程正在堆里分配内存,堆锁(heap lock)将不会被释放。
    3.如果目标线程在结束时调用了某些kernel32,会造成kernel32的状态不一致。
    4.如果目标线程正在更改一个共享DLL的全局状态,这个共享DLL的状态可能会被破坏,影响到其他的正在使用这个DLL库的线程。

    (范例:经常会出现程序卡死,不能退出的情况)

    #include <stdio.h>
    #include <time.h>
    #include <Windows.h>
    
    DWORD WINAPI Thread(void *arg) {
        while (1) {
            printf("Run #%d\n", (int)time(NULL));
            Sleep(1000);
        }
        return 0;
    }
    
    int main(void) {
        HANDLE hThread = CreateThread(NULL, 0, Thread, NULL, 0, NULL);
    
        Sleep(3000); // 3s后强制结束线程hTread,线程退出码为12345
        TerminateThread(hThread, 12345);
    
        DWORD exitCode;
        while (1) {
            GetExitCodeThread(hThread, &exitCode); // 严重浪费 CPU 时间
            printf("exitCode=%lu\n", exitCode);
            if (STILL_ACTIVE != exitCode)
                break;
    
        }
    
        CloseHandle(hThread);
        return 0;
    }

    (某次正常的退出结果)
    11

    做法三:使用信号(Signals)(行不通)

    在Unix系统中,signals 是跨进程传送通告(notifications)的标准方法,SIGTERM 相当于“请你离开”的意思,SIGKILL 则是粗略相当于 TerminateThread()。

    这个点子似乎不错,因为 C runtime library 支持标准的 signals,如SIGABRT 和 SIGINT。各种 signals 的处理函数可以利用 C 函数 signal() 设立之。
    但是我很快就进入了一个死胡同。C runtime 函数中没有一个名为 kill(),而那是 Unix 系统藉以送出 signal 的操作。是有一个 raise() 啦,但只能够传
    送 signal 给目前的线程。

    观察过 C runtime library 的源代码之后,我发现 signals 其实是利用Win32 的异常情况(exceptions)模拟的,Win32 之中并没有真正的 signals,所以这个想法也行不通。

    做法四:跨越线程,丢出异常情况(Exceptions)(Win32 API不支持)

    在目标线程中引发一个异常情况(exception)。如果有必要在结束前清理某些东西,目标线程可以设法捕捉此一异常情况,否则它可以什么都不管地直接结束自己的生命。
    经过数个小时的努力之后,我可以很确定地告诉各位, Win32 API 中没有什么标准方法可以把一个异常情况丢到另一个线程中

    做法五:设立一个标记

    缺点线程需要一个 polling 机制,时时检查标记值,以决定该不该结束自己。
    解决上述缺点:不是写一个 busy loop 来检验标记值,而是使用一个手动重置(manual-reset)的 event 对象。 Worker 线程可以检查该 event 对象的状态或是等待它,视情况而定。

    Event对象范例参考:Win32线程——在某个线程内终止另一个正在运行的线程(2)(Event对象)

    展开全文
  • 如何关掉一个线程

    千次阅读 2019-01-31 12:15:00
    一个线程在运行状态,其中断标志被设置为true,则此后,一旦线程调用了wait、jion、sleep方法的一种,立马抛出一个InterruptedException,且中断标志被清除,重新设置为false。 如果非阻塞---标志位置为true ...
  • 简单实现一个 js 多线程

    千次阅读 2019-04-13 20:00:58
    简单实现一个 js 的多线程执行和多线程之间数据的传递 JS作为脚本语言,它的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。(这里这些问题我们不做研究) 但是单线程的...
  • Java如何安全终止一个线程

    万次阅读 2018-07-20 16:37:16
    最初的JDK版本,Thread类提供了一个线程终止的方法stop()方法,但是现在JDK源码发现,stop()方法已经被废弃。主要原因是:stop()方法太过暴力。强制终止一个正在执行的线程。这样的话会造成一些数据不一致...
  • Thread thread = new Thread(SendOtherData); thread.Start();
  • 有时开启一个线程是为了把耗时的操作转移到线程中执行,主进程可以执行其它的任务,避免了因为大量的重复性操作导致主进程阻塞。 控制线程暂停的方法: 线程的同步用到了QMutex类,作为一个互斥锁控制进行保护。...
  • 主要介绍了C语言如何正确的终止正在运行的子线程,小编觉得挺不错的,现在分享给大家,也给大家做参考。一起跟随小编过来看看吧
  • WPF取消一个线程的执行

    千次阅读 2020-08-01 13:14:16
    WPF从非UI线程中更新UI元素 添加一个按钮,用于点击时取消线程的执行: 声明一个 CancellationTokenSource 类型的对象,这个对象用于发送一个信号,如下所示: private CancellationTokenSource tokenSource = ...
  • 调试,出现这个错误的原因,我网上查了很多。...如果要在另一个线程中修改控件的Text属性(例如:ListBox控件类型的 lbConnected),如果直接写:lbStatus.Items.Add(str); 的话就会出现上述错误
  • QT (启动一个线程)

    万次阅读 2018-12-01 17:06:47
    (2) 自己的WorkThreak类重新实现run()函数, 该函数是一个死循环, 主要是完成自己需要的功能代码 (3) 使用自己的类WorkThread 实例一个对象,也就是用该类创建一个变量 如: WorkThread *task = new WorkThread ...
  • WinForm 线程中打开一个新窗体

    千次阅读 2019-08-17 21:41:28
    项目有个动作:打开一个窗体展示 FormToast toast = new FormToast(); toast.lblMsg.Text = str; toast.Show(); 大多数情况,直接界面上(主线程)点击按钮的时候展示,没问题。 有些特殊情况,是新开的子...
  • destory() 和 stop() 方法都过时了,用了还报错,fatal error 错误,怎么正确的关闭线程
  • 1.创建并启动线程的6种方式: 1)继承Thread类创建线程 2)实现Runnable接口创建线程 ...6)定时器Timer (底层封装了一个TimerThread对象) 1.1 继承Thread类创建线程 1.1.1继承Thread类方式创建线程的...
  • 调用线程无法访问此对象,因为另一个线程拥有该对象问题,这种情况往往很常见,比如:说Timers和DoubleAnimation也就是计时器和动画一起使用就会出来这个错误。 其实加上一句话就行了,也就是设置线程的有优先级,...
  • 关于java怎么终止一个线程的执行

    千次阅读 2016-10-15 22:54:06
    其实现在要对一个循环执行的线程关闭,对循环执行体设置执行标志是常见的方法。另外一种方法是使用interrupt方法中断线程方式关闭线程。使用interrupt方法中断线程来退出线程sleep wait io阻塞的情况下,对于这种...
  • 不能类下调用@Async注解的方法,比如A类下有a和b方法,b方法有@Async注解,不能直接这样a调用b,要把b放到其他类 @Async也可以打类上,这样类下面的所有方法都是异步的(被其他类调用的时候) 要实现启动时加载...
  • JavaThrowable分为Exception和Error: 出现Error的情况下,程序会停止运行。Exception分为RuntimeException和非运行时异常。非运行时异常必须处理,比如threadsleep()时,必须处理InterruptedException异常,...
  • 例如: for (int i = 0; i ; i++) { ...如何关闭其中的一个线程呢? 请下载解决方案。 呵呵,这个实例10分值的买, 觉得好的话就评个分吧,评分后会返回你11分 (一定要评分,光评论是不返分的)
  • (2)或定义一个全局bool变量bIsRunning设为true,外部要关闭时,将这个变量设为false。  线程函数内部循环来检测这个变量,当为false时就返回。如:  while(bIsRunning)  {   return 0;  } 
  • 我的意思是程序A循环调用一个exe,这个exe有可能发生崩溃的情况,所以我想用 一个程序实时监视这种情况(此时表现为exe一直占用进程),一旦exe崩溃可以把 这个exe的进程杀掉。 能不能通过判断exe占用进程的时间...
  • C#如何优雅的终止一个线程

    万次阅读 2017-10-11 13:28:56
    大家都知道C#里面,我们可以使用Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Thread.Abort方法后线程就立刻停止了吗?...
  • 前面几篇是介绍tkinter GUI编程的,我想这个有时间得出一个系列的,比较完整能够入门的教程。好了本文介绍threading模块,中文的意思是线程。...说线程一个轻量级的进程,多个线程共享进程的资源。线程

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 614,964
精华内容 245,985
关键字:

在一个线程中关闭另一个线程