thread 订阅
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。一个进程可以有很多线程,每条线程并行执行不同的任务。在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。 展开全文
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。一个进程可以有很多线程,每条线程并行执行不同的任务。在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。
信息
提出者
dozer
定    义
程序执行流的最小单元
多线程中
CPU的基本单位
应用学科
计算机
中文名
线程
外文名
thread
别    称
执行绪;轻量进程
线程发展简史
线程的引入:60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。因此在80年代,出现了能独立运行的基本单位——线程(Threads)。
收起全文
精华内容
参与话题
问答
  • JAVA核心知识点--Thread线程基础

    万次阅读 多人点赞 2017-03-26 17:37:49
    继承java.lang.Thread类 实现java.lang.Runnable接口 三、线程的状态 四、线程的基本方法和属性 五、线程资源共享示例 一、什么是线程? 线程是一个程序的多个执行路径,执行调度的单位,依托于进程而存在。 ...

    目录

    一、什么是线程?

    二、线程的创建

    继承java.lang.Thread类

    实现java.lang.Runnable接口

    三、线程的状态

    四、线程的基本方法和属性

    五、线程资源共享示例


    一、什么是线程?

    线程是一个程序的多个执行路径,执行调度的单位,依托于进程而存在。 线程不仅可以共享进程的内存,而且还拥有一个属于自己的内存空间,这段内存空间也叫做线程栈,是在建立线程时由系统分配的,主要用来保存线程内部所使用的数据,如线程执行函数中所定义的变量。

    注意:Java中的多线程是一种抢占机制而不是分时机制。抢占机制指的是有多个线程处于可运行状态,但是只允许一个线程在运行,他们通过竞争的方式抢占CPU。  

    二、线程的创建

    在Java中可以通过以下两种方式定义线程:

    • 继承java.lang.Thread类 。
    • 实现java.lang.Runnable接口。

    继承java.lang.Thread类

    /**
     * 通过继承java.lang.Thread类来定义线程
     */
    public class MyThread extends Thread {
    
    	private boolean flag = true;
    
    	public MyThread(String threadName) {
    		super(threadName);
    	}
    
    	@Override
    	public void run() {
    		while (flag) {
    			System.out.println(Thread.currentThread().getName()
    					+ " Is Running...");
    		}
    	}
    
    	public void shutDown() {
    		this.flag = false;
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    		MyThread myThread = new MyThread("MyThread");
    		myThread.start();
    		Thread.sleep(1000);
    		myThread.shutDown();
    
    	}
    }
    

    实现java.lang.Runnable接口

    /**
     * 通过实现Runnable接口来定义线程
     */
    public class MyThread implements Runnable {
    	private boolean flag = true;
    
    	@Override
    	public void run() {
    		while (flag) {
    			System.out.println(Thread.currentThread().getName()
    					+ " Is Running...");
    		}
    	}
    
    	public void shutDown() {
    		this.flag = false;
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    
    		MyThread myThread = new MyThread();
    		Thread thread = new Thread(myThread, "MyThread");
    		thread.start();
    		Thread.sleep(1000);
    		myThread.shutDown();
    
    	}
    }
    

    在线程的start()方法被调用后,JVM会自动调用线程的run()方法来执行任务。start()方法结束,线程也就终止了。

    注意:推荐使用实现Runnable接口的方式来定义线程,因为Java中的类只支持单继承,你一旦继承了Thread类就不能再继承其他的类了,会大大降低程序的可扩展性和灵活性。  

    三、线程的状态

    四、线程的基本方法和属性

    1)优先级(priority)

    每个线程都有一个优先级(用1-10的整数表示,默认优先级是5,高优先级线程的执行优先于低优先级线程。默认一个线程的优先级和创建他的线程优先级相同。

    以下是Thread定义的三个与优先级相关的静态常量: 

    MAX_PRIORITY =10
    NORM_PRIORITY =5
    MIN_PRIORITY=1

    2)Thread.sleep(long millis)/sleep(long millis)

    使当前线程休眠(暂停执行)millis毫秒的时间(millis指定的休眠时间是其最小的不执行时间,因为在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级);sleep()是Thread类的static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用sleep()方法时,线程虽然休眠了,但是对象的机锁并没有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。 

    作用:保持对象锁,让出CPU,调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留一定的执行机会给其他线程;

    3)Thread.yield()

    让出CPU的使用权,让其他同等优先级或更高优先级的线程可以获取到运行机会,线程yield()时也不会释放对象锁。

    sleep()和yield()的区别:

    • sleep()方法会给其他线程运行的机会,而不考虑其他线程的优先级,因此会给较低优先级线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。 
    • 当线程执行了sleep(long millis)方法后,将转到阻塞状态,参数millis指定休眠时间;当线程执行了yield()方法后,将转到就绪状态。 
    • sleep()方法声明抛出InterruptedException异常,而yield()方法没有声明抛出任何异常 。

    4)thread.join()

    线程合并,使用该方法的线程会在此线程执行完毕后才往下继续执行,可使异步线程变为同步线程。

    5)object.wait()

    wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁),其他线程可以访问。执行wait()方法的线程必须拥有当前对象的锁,如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常,所以wait()必须在synchronized block中调用。

    wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。

    6)object.notify()/notifyAll()

    唤醒在当前对象等待池中等待的一个线程/所有线程。notify()/notifyAll()也必须拥有相同对象锁,否则也会抛出IllegalMonitorStateException异常。

    7)Synchronized Block

    Java中的每一个对象都有唯一的一个内置的锁,每个Synchronized Block或同步的方法只有持有调用该方法被锁定对象的锁的线程才可以访问,否则所属线程阻塞;机锁具有独占性、一旦被一个Thread持有,其他的Thread就不能再拥有(不能访问其他同步方法),方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。

    五、线程资源共享示例

    /**
     * 车站售票示例
     */
    public class TicketsThread implements Runnable {
    
    	// 车票总数
    	private Integer tickets = 100;
    	private boolean flag = true;
    	private Object object = new Object();
    
    	@Override
    	public void run() {
    		while (flag) {
    			/*	synchronized (object) {
    				if (tickets > 0) {
    					try {
    						Thread.sleep(100);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + "售出第"
    							+ tickets + "张车票");
    					tickets--;
    				} else {
    					System.out.println(Thread.currentThread().getName()
    							+ "提醒广大乘客:车票已经售完,停止售票!");
    					this.flag = false;
    				}
    			}*/
    			sell();
    		}
    
    	}
    
    	private  synchronized void sell(){
    		if (tickets > 0) {
    			try {
    				Thread.sleep(100);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println(Thread.currentThread().getName() + "售出第"
    					+ tickets + "张车票");
    			tickets--;
    		} else {
    			System.out.println(Thread.currentThread().getName()
    					+ "提醒广大乘客:车票已经售完,停止售票!");
    			this.flag = false;
    		}
    	}
    	
    	public void shutDown() {
    		this.flag = false;
    	}
    
    	public static void main(String[] args) {
    		TicketsThread ticketsThread = new TicketsThread();
    		Thread thread1 = new Thread(ticketsThread, "售票处1");
    		Thread thread2 = new Thread(ticketsThread, "售票处2");
    		Thread thread3 = new Thread(ticketsThread, "售票处3");
    
    		thread1.start();
    		thread2.start();
    		thread3.start();
    
    	}
    
    }
    /**
     * 死锁示例
     */
    public class DeadThread implements Runnable {
    
    	private Object obj1 = new Object();
    	private Object obj2 = new Object();
    
    	private boolean flag = true;
    
    	@Override
    	public void run() {
    		if (flag) {
    			synchronized (obj1) {
    				try {
    					Thread.sleep(500);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				synchronized (obj2) {
    
    				}
    			}
    		} else {
    			synchronized (obj2) {
    				try {
    					Thread.sleep(500);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				synchronized (obj1) {
    
    				}
    			}
    		}
    
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    		DeadThread deadThread = new DeadThread();
    		Thread thread1 = new Thread(deadThread);
    		Thread thread2 = new Thread(deadThread);
    		thread1.start();
    		Thread.sleep(100);
    		deadThread.flag = false;
    		thread2.start();
    
    	}
    
    }

      

    展开全文
  • Thread详解

    千次阅读 2018-06-01 15:49:41
    1.1什么是线程?  线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被...

    1.1什么是线程? 

    线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

      线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

     1.2 什么是线程安全性?

    如果一个类可以安全地被多个线程使用,它就是线程安全的。你无法对此论述提出任何争议,但也无法从中得到更多有意义的帮助。那么我们如何辨别线程安全与非线程安全的类?我们甚至又该如何理解“安全”呢?任何一个合理的“线程安全性”定义,其关键在于“正确性”的概念。在<<JAVA并发编程实践>>书中作者是这样定义的:一个类是是线程安全的,是指在被多个线程访问时,类可以持续进行正确的行为。或当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用方代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的。

     1.3 线程的六种状态

    线程从创建到销毁期间有六种状态:

    • New: 至今尚未启动的线程的状态。 
    • Runnable :可运行线程的线程状态。
    • Blocked :受阻塞并且正在等待监视器锁的某一线程的线程状态。
    • Waiting :某一等待线程的线程状态。
    • Timed_waiting:具有指定等待时间的某一等待线程的线程状态。
    • Terminated:已终止线程的线程状态。线程已经结束执行。
    • 如下图所示:
    •  

     

     

     

    二、Thread类

       2.1 属性

    [java] view plain copy

    1. //线程名字,通过构造参数来指定  
    2. private char        name[];  
    3. //表示线程的优先级,优先级越高,越优先被执行(最大值为10,最小值为1,默认值为5)  
    4. private int         priority;  
    5.   
    6. private Thread      threadQ;  
    7. private long        eetop;  
    8.   
    9. /* Whether or not to single_step this thread. */  
    10. private boolean     single_step;  
    11.   
    12. //线程是否是守护线程:当所有非守护进程结束或死亡后,程序将停止   
    13. private boolean     daemon = false;  
    14.   
    15. /* JVM state */  
    16. private boolean     stillborn = false;  
    17.   
    18. //将要执行的任务  
    19. private Runnable target;  
    20.   
    21. /* 线程组表示一个线程的集合。此外,线程组也可以包含其他线程组。线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组。  */  
    22. private ThreadGroup group;  
    23.   
    24. /* The context ClassLoader for this thread */  
    25. private ClassLoader contextClassLoader;  
    26.   
    27. /* The inherited AccessControlContext of this thread */  
    28. private AccessControlContext inheritedAccessControlContext;  
    29.   
    30. /*第几个线程,在init初始化线程的时候用来赋给thread.name */    
    31. private static int threadInitNumber;  
    32. private static synchronized int nextThreadNum() {  
    33.     return threadInitNumber++;  
    34. }  
    35.   
    36. /* ThreadLocal values pertaining to this thread. This map is maintained 
    37.  * by the ThreadLocal class. */  
    38. ThreadLocal.ThreadLocalMap threadLocals = null;  
    39.   
    40. /* 
    41.  * InheritableThreadLocal values pertaining to this thread. This map is 
    42.  * maintained by the InheritableThreadLocal class. 
    43.  */  
    44. ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;  
    45.   
    46. /* 
    47.  * The requested stack size for this thread, or 0 if the creator did 
    48.  * not specify a stack size.  It is up to the VM to do whatever it 
    49.  * likes with this number; some VMs will ignore it. 
    50.  */  
    51. private long stackSize;  
    52.   
    53. /* 
    54.  * JVM-private state that persists after native thread termination. 
    55.  */  
    56. private long nativeParkEventPointer;  
    57.   
    58. /* 
    59.  * Thread ID 
    60.  */  
    61. private long tid;  
    62.   
    63. /* For generating thread ID */  
    64. private static long threadSeqNumber;  
    65.   
    66. /* 
    67.  *线程从创建到最终的消亡,要经历若干个状态。 
    68.  *一般来说,线程包括以下这几个状态:创建(new)、就绪(runnable)、运行(running)、阻塞(blocked)、time waiting、waiting、消亡(dead)。 
    69.  *  
    70.  */  
    71. private volatile int threadStatus = 0;  

       2.3 start()操作

    [java] view plain copy

    1. //启动新创建的线程  
    2. public synchronized void start() {  
    3.     /** 
    4.      * This method is not invoked for the main method thread or "system" 
    5.      * group threads created/set up by the VM. Any new functionality added 
    6.      * to this method in the future may have to also be added to the VM. 
    7.      * 
    8.      * A zero status value corresponds to state "NEW". 
    9.      */  
    10.     /*这个方法不会被主线程调用或通过虚拟机系统线程组创建起来。未来任何添加到该方法里的新功能可能需要加入到虚拟机中 
    11.      *  
    12.      * 状态new的值是0. 
    13.      * */  
    14.     if (threadStatus != 0)  
    15.         throw new IllegalThreadStateException();  
    16.   
    17.     /* Notify the group that this thread is about to be started 
    18.      * so that it can be added to the group's list of threads 
    19.      * and the group's unstarted count can be decremented. */  
    20.     /* 通知线程组新线程将要启动,以便它可以添加到线程组列表并且线程组没有开始计数*/  
    21.     group.add(this);  
    22.   
    23.     boolean started = false;  
    24.     try {  
    25.         start0();  
    26.         started = true;  
    27.     } finally {  
    28.         try {  
    29.             if (!started) {  
    30.                 group.threadStartFailed(this);  
    31.             }  
    32.         } catch (Throwable ignore) {  
    33.             /* do nothing. If start0 threw a Throwable then 
    34.               it will be passed up the call stack */  
    35.         }  
    36.     }  
    37. }  

       2.3 run()操作

    [java] view plain copy

    1. public void run() {  
    2.        if (target != null) {  
    3.             target.run();  
    4.        }  
    5.  }  

       2.4 start()和run()之间有什么区别?

       2.4.1 代码示例:run()方法使用

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. /** 
    4.  *  
    5.  * @author liulongling 
    6.  * 
    7.  */  
    8. public class ThreadTest extends Thread{  
    9.   
    10.     public ThreadTest(String name) {  
    11.         super.setName(name);  
    12.     }  
    13.   
    14.     @Override  
    15.     public void run() {  
    16.         for(int i = 0; i < 5;i++)  
    17.         {  
    18.             System.out.println(super.getName()+":"+i);  
    19.         }  
    20.     }  
    21.   
    22.     public static void main(String[] args) {  
    23.         ThreadTest test = new ThreadTest("A");  
    24.         ThreadTest test1 = new ThreadTest("B");  
    25.           
    26.         test.run();  
    27.         test1.run();  
    28.           
    29.         if(Thread.activeCount()>=1)  
    30.         {  
    31.             Thread.yield();  
    32.         }  
    33.     }  
    34. }  
    控制台:
    +------------------------------------------------------------------+
    

    A:0 A:1 A:2 A:3 A:4 B:0 B:1 B:2 B:3 B:4

    +------------------------------------------------------------------+

       2.4.2 代码示例:start()方法使用

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. /** 
    4.  *  
    5.  * @author liulongling 
    6.  * 
    7.  */  
    8. public class ThreadTest extends Thread{  
    9.   
    10.     public ThreadTest(String name) {  
    11.         super.setName(name);  
    12.     }  
    13.   
    14.     @Override  
    15.     public void run() {  
    16.         for(int i = 0; i < 5;i++)  
    17.         {  
    18.             System.out.println(super.getName()+":"+i);  
    19.         }  
    20.     }  
    21.   
    22.     public static void main(String[] args) {  
    23.         ThreadTest test = new ThreadTest("A");  
    24.         ThreadTest test1 = new ThreadTest("B");  
    25.           
    26.         test.start();  
    27.         test1.start();  
    28.           
    29.         if(Thread.activeCount()>=1)  
    30.         {  
    31.             Thread.yield();  
    32.         }  
    33.     }  
    34. }  
    控制台:
    +------------------------------------------------------------------+
    

    B:0 A:0 B:1 A:1 B:2 A:2 B:3 A:3 B:4 A:4

    +------------------------------------------------------------------+

       2.4.3 结果分析

       以上结果可以发现run()和单线程一样每次只能执行一个线程,而start()不一样有多个线程交叉执行着。我们知道start()方法被用来启动新创建的线程,而且start()内部通过本地系统调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法会启动新的线程,其中多个线程在CPU中是支持并发执行的。那么有没有什么方法可以让A线程优先执行呢?

     

       2.5 setPriority()操作

     

     

    [java] view plain copy

    1. public final void setPriority(int newPriority) {  
    2.        ThreadGroup g;  
    3.        checkAccess();  
    4.        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {  
    5.            throw new IllegalArgumentException();  
    6.        }  
    7.        if((g = getThreadGroup()) != null) {  
    8.            if (newPriority > g.getMaxPriority()) {  
    9.                newPriority = g.getMaxPriority();  
    10.            }  
    11.            setPriority0(priority = newPriority);  
    12.        }  
    13.    }  

    [java] view plain copy

    1. private native void setPriority0(int newPriority);  

     

       setPriority使用了native关键字,在Java API中,一个native方法意味着这个方法没有使用Java语言实现,只能通过代码示例去分析它的原理。在代码中将线程A的执行优先级设置为最高,同时线程B的优先级设置为最低,那么预期的结果应该是线程A先执行完后再执行线程B,代码如下:

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. /** 
    4.  *  
    5.  * @author liulongling 
    6.  * 
    7.  */  
    8. public class ThreadTest extends Thread{  
    9.   
    10.     public ThreadTest(String name) {  
    11.         super.setName(name);  
    12.     }  
    13.   
    14.     @Override  
    15.     public void run() {  
    16.         for(int i = 0; i < 5;i++)  
    17.         {  
    18.             System.out.println(super.getName()+":"+i);  
    19.         }  
    20.     }  
    21.   
    22.     public static void main(String[] args) {  
    23.         ThreadTest test = new ThreadTest("A");  
    24.         ThreadTest test1 = new ThreadTest("B");  
    25.         //MAX_PRIORITY是最高优先级  
    26.         test.setPriority(MAX_PRIORITY);  
    27.           
    28.         test.setPriority(MIN_PRIORITY);  
    29.         test.start();  
    30.         test1.start();  
    31.           
    32.         if(Thread.activeCount()>=1)  
    33.         {  
    34.             Thread.yield();  
    35.         }  
    36.     }  
    37. }  
    控制台:
    +------------------------------------------------------------------+
    A:0
    A:1
    A:2
    A:3
    A:4
    B:0
    B:1
    B:2
    B:3
    B:4
    +------------------------------------------------------------------+

       2.5 sleep(long millis)操作

     

    [java] view plain copy

    1. public static native void sleep(long millis) throws InterruptedException;  

     

      sleep也是使用了native关键字,调用了底层方法。sleep是指线程被调用时,占着CPU不工作,形象地说明为“占着CPU睡觉”,此时,系统的CPU部分资源被占用,其他线程无法进入。多线程下使用时需要注意的是sleep方法不会释放锁。比如:线程A和线程B执行一段加锁代码,线程A先进去,线程B在外面等待,其中代码程序有sleep方法让线程休眠,休眠后锁并不会被释放,线程B也只能继续在外面等待直到休眠时间结束。代码如下:

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. /** 
    6.  *  
    7.  * @author liulongling 
    8.  * 
    9.  */  
    10. public class ThreadTest{  
    11.   
    12.     private int i = 10;  
    13.     private Object object = new Object();  
    14.       
    15.     MyThread thread1 = new MyThread("A");  
    16.     MyThread thread2 = new MyThread("B");  
    17.        
    18.     public static void main(String[] args) throws IOException  {  
    19.         ThreadTest test = new ThreadTest();  
    20.         test.thread1.start();  
    21.         test.thread2.start();  
    22.     }   
    23.        
    24.        
    25.     class MyThread extends Thread{  
    26.         public MyThread(String name) {  
    27.             super.setName(name);  
    28.         }  
    29.         @Override  
    30.         public void run() {  
    31.             synchronized (object) {  
    32.                 System.out.println(Thread.currentThread().getName()+":"+i++);  
    33.                 try {  
    34.                     System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
    35.                     Thread.currentThread().sleep(1000);  
    36.                 } catch (InterruptedException e) {  
    37.                     // TODO: handle exception  
    38.                 }  
    39.                 System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");  
    40.                 System.out.println(Thread.currentThread().getName()+":"+i);  
    41.             }  
    42.         }  
    43.     }  
    44. }  

     

    控制台:
    +------------------------------------------------------------------+
    

     

    A:10

    线程A进入睡眠状态

    线程A被唤醒

    A:11

    B:11

    线程B进入睡眠状态

    线程B被唤醒

    B:12

    +------------------------------------------------------------------+

       2.6 yield()操作

     

       调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

     

     注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

       2.7 isAlive()   

     

    [java] view plain copy

    1. /** 
    2.  * Tests if this thread is alive. A thread is alive if it has 
    3.  * been started and has not yet died. 
    4.  * 
    5.  * @return  <code>true</code> if this thread is alive; 
    6.  *          <code>false</code> otherwise. 
    7.  */  
    8. public final native boolean isAlive();  

      表示线程当前是否为可用状态,如果线程已经启动,并且当前没有任何异常的话,则返回true,否则为false

     

       2.8 join()操作

      join有3个重载方法:

     

       2.8.1 join() 

     

    [java] view plain copy

    1. //立即阻塞调用线程,直到该线程执行结束  
    2. public final synchronized void join(long millis)  
    3.         throws InterruptedException {  
    4.     long base = System.currentTimeMillis();  
    5.     long now = 0;  
    6.   
    7.     if (millis < 0) {  
    8.         throw new IllegalArgumentException("timeout value is negative");  
    9.     }  
    10.   
    11.     if (millis == 0) {  
    12.         //线程状态正常  
    13.         while (isAlive()) {  
    14.             wait(0);  
    15.         }  
    16.     } else {  
    17.         while (isAlive()) {  
    18.             long delay = millis - now;  
    19.             if (delay <= 0) {  
    20.                 break;  
    21.             }  
    22.             wait(delay);  
    23.             now = System.currentTimeMillis() - base;  
    24.         }  
    25.     }  
    26. }  

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. /** 
    6.  *  
    7.  * @author liulongling 
    8.  * 
    9.  */  
    10. public class ThreadTest{  
    11.   
    12.     private int i = 10;  
    13.     private Object object = new Object();  
    14.   
    15.     MyThread thread1 = new MyThread("A");  
    16.     MyThread thread2 = new MyThread("B");  
    17.   
    18.     public static void main(String[] args) throws IOException  {  
    19.         ThreadTest test = new ThreadTest();  
    20.         test.thread1.start();  
    21.         System.out.println("线程"+Thread.currentThread().getName()+"等待");  
    22.         try {  
    23.             test.thread1.join();  
    24.         } catch (InterruptedException e) {  
    25.             // TODO Auto-generated catch block  
    26.             e.printStackTrace();  
    27.         }  
    28.         System.out.println("线程"+Thread.currentThread().getName()+"执行");  
    29.         for (int j = 0; j < 5; j++)  
    30.         {  
    31.             System.out.println(Thread.currentThread().getName() + ":" + j);  
    32.         }  
    33.     }   
    34.   
    35.   
    36.     class MyThread extends Thread{  
    37.         public MyThread(String name) {  
    38.             super.setName(name);  
    39.         }  
    40.         @Override  
    41.         public void run() {  
    42.             synchronized (object) {  
    43.                 System.out.println(Thread.currentThread().getName()+":"+i++);  
    44.                 try {  
    45.                     System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
    46.                     Thread.currentThread().sleep(1000);  
    47.                 } catch (InterruptedException e) {  
    48.                     // TODO: handle exception  
    49.                 }  
    50.                 System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");  
    51.                 System.out.println(Thread.currentThread().getName()+":"+i);  
    52.             }  
    53.         }  
    54.     }  
    55. }  
    控制台:
    +------------------------------------------------------------------+
    

     

    线程main等待

    A:10

    线程A进入睡眠状态

    线程A被唤醒

    A:11

    线程main执行

    main:0

    main:1

    main:2

    main:3

    main:4

     

      MSDN上解释join无参方法其作用为:阻塞 “调用线程” 直到某个线程结束。从上面结果可以分析出,A线程其实在main线程上运行,我们可以说main线程调用了A线程或称main线程为“调用线程”,A线程调用join()方法后将调用线程阻塞直到A线程结束后控制台才输出来main:0...。我们去掉join方法看下控制台输出结果。

     

    控制台:
    +------------------------------------------------------------------+

     

     

    main:0

    main:1

    A:10

    main:2

    线程A进入睡眠状态

    main:3

    main:4

    线程A被唤醒

    A:11

    +------------------------------------------------------------------+

       2.8.2 join(long millis)

      join(long millis)的参数作用是指定“调用线程”的最大阻塞时间。代码如下:

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. /** 
    6.  *  
    7.  * @author liulongling 
    8.  * 
    9.  */  
    10. public class ThreadTest{  
    11.   
    12.     private int i = 10;  
    13.     private Object object = new Object();  
    14.   
    15.     MyThread thread1 = new MyThread("A");  
    16.     MyThread thread2 = new MyThread("B");  
    17.   
    18.     public static void main(String[] args) throws IOException  {  
    19.         ThreadTest test = new ThreadTest();  
    20.         test.thread1.start();  
    21.         System.out.println("线程"+Thread.currentThread().getName()+"等待");  
    22.         try {  
    23.             test.thread1.join(500);  
    24.         } catch (InterruptedException e) {  
    25.             // TODO Auto-generated catch block  
    26.             e.printStackTrace();  
    27.         }  
    28.         System.out.println("线程"+Thread.currentThread().getName()+"执行");  
    29.         for (int j = 0; j < 5; j++)  
    30.         {  
    31.             System.out.println(Thread.currentThread().getName() + ":" + j);  
    32.         }  
    33.     }   
    34.   
    35.   
    36.     class MyThread extends Thread{  
    37.         public MyThread(String name) {  
    38.             super.setName(name);  
    39.         }  
    40.         @Override  
    41.         public void run() {  
    42.             synchronized (object) {  
    43.                 System.out.println(Thread.currentThread().getName()+":"+i++);  
    44.                 try {  
    45.                     System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
    46.                     Thread.currentThread().sleep(1000);  
    47.                 } catch (InterruptedException e) {  
    48.                     // TODO: handle exception  
    49.                 }  
    50.                 System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");  
    51.                 System.out.println(Thread.currentThread().getName()+":"+i);  
    52.             }  
    53.         }  
    54.     }  
    55. }  

     

    
     

     

    线程main等待

    A:10

    线程A进入睡眠状态

    线程main执行

    main:0

    main:1

    main:2

    main:3

    main:4

    线程A被唤醒

    A:11

     

    +------------------------------------------------------------------+   从上面结果可以分析出,在A线程还未结束,主线程已经开始执行。原因是我们给主线程设置的阻塞时间是500ms,小于A线程run()方法里的1000ms休眠时间。

       2.8.3 join(long millis, int nanos)

      阻塞调用线程的时间最长为 millis 毫秒 + nanos 纳秒...这里就不举例说明了,原理和上一个方法一样。

     

     

     

       2.9 interrupt()操作

     

      interrupt的作用是中断正被阻塞的线程,比如我给某一线程休眠了10s时间,如果我在这个线程上调用了interrupt方法,看看会有什么效果。代码如下:

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. /** 
    6.  *  
    7.  * @author liulongling 
    8.  * 
    9.  */  
    10. public class ThreadTest{  
    11.   
    12.     private int i = 10;  
    13.     private Object object = new Object();  
    14.   
    15.     MyThread thread1 = new MyThread("A");  
    16.     MyThread thread2 = new MyThread("B");  
    17.   
    18.     public static void main(String[] args) throws IOException  {  
    19.         ThreadTest test = new ThreadTest();  
    20.         test.thread1.start();  
    21.         test.thread1.interrupt();  
    22.     }   
    23.   
    24.   
    25.     class MyThread extends Thread{  
    26.         public MyThread(String name) {  
    27.             super.setName(name);  
    28.         }  
    29.         @Override  
    30.         public void run() {  
    31.             synchronized (object) {  
    32.                 System.out.println(Thread.currentThread().getName()+":"+i++);  
    33.                 try {  
    34.                     System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
    35.                     Thread.currentThread().sleep(10000);  
    36.                 } catch (InterruptedException e) {  
    37.                     System.out.println("你被中断了");  
    38.                 }  
    39.                 System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");  
    40.                 System.out.println(Thread.currentThread().getName()+":"+i);  
    41.             }  
    42.         }  
    43.     }  
    44. }  
    控制台:
    +------------------------------------------------------------------+

     

    A:10

    线程A进入睡眠状态

    你被中断了

    线程A被唤醒

    A:11 +------------------------------------------------------------------+

     使用了 interrupt的结果是在休眠代码处抛出一个异常,并且阻塞马上停止了。

     

       3.0 setDaemon()操作

      用来设置线程是否成为守护线程和判断线程是否是守护线程。
      守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。Thread类有一个比较常用的静态方法currentThread()用来获取当前线程。

    展开全文
  • Thread

    千次阅读 2018-03-25 15:41:09
    1 start方法 start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要...注意,继承Thread类必须重写run方法,在run方法中定义具体要...

     1 start方法

      start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。

      2 run方法

      run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当线程获得了CPU执行时间,便进入run方法体去执行具体的任务。注意,继承Thread类必须重写run方法,在run方法中定义具体要执行的任务。

    补充:用start()方法来启动线程,是真正实现了多线程,通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,无需等待run方法执行完毕,即可继续执行下面的代码。

    所以说:

    start()方法是真正实现了多线程run()方法只是一个普通的方法。

      3 sleep方法

      sleep方法有两个重载版本:

    1
    2
    3
    sleep(long millis)     //参数为毫秒
     
    sleep(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒
      
      sleep相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。

         但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。看下面这个例子就清楚了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    public class Test {
         
        private int i = 10;
        private Object object = new Object();
         
        public static void main(String[] args) throws IOException  {
            Test test = new Test();
            MyThread thread1 = test.new MyThread();
            MyThread thread2 = test.new MyThread();
            thread1.start();
            thread2.start();
        
         
         
        class MyThread extends Thread{
            @Override
            public void run() {
                synchronized (object) {
                    i++;
                    System.out.println("i:"+i);
                    try {
                        System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
                        Thread.currentThread().sleep(10000);
                    catch (InterruptedException e) {
                        // TODO: handle exception
                    }
                    System.out.println("线程"+Thread.currentThread().getName()+"睡眠结束");
                    i++;
                    System.out.println("i:"+i);
                }
            }
        }
    }

    Thread.currentThread().getName() 此方法的作用是获取线程名

    输出结果:

      从上面输出结果可以看出,当Thread-0进入睡眠状态之后,Thread-1并没有去执行具体的任务。只有当Thread-0执行完之后,此时Thread-0释放了对象锁,Thread-1才开始执行。

      注意,如果调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出。当线程睡眠时间满后,不一定会立即得到执行,因为此时可能CPU正在执行其他的任务。所以说调用sleep方法相当于让线程进入阻塞状态。

      4)yield方法

      调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

      注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

      5)join方法

      join方法有三个重载版本:

    1
    2
    3
    join()
    join(long millis)     //参数为毫秒
    join(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒

       假如在main线程中,调用thread.join方法,则main方法会等待thread线程执行完毕或者等待一定的时间。如果调用的是无参join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的时间。

      看下面一个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public class Test {
         
        public static void main(String[] args) throws IOException  {
            System.out.println("进入线程"+Thread.currentThread().getName());
            Test test = new Test();
            MyThread thread1 = test.new MyThread();
            thread1.start();
            try {
                System.out.println("线程"+Thread.currentThread().getName()+"等待");
                thread1.join();
                System.out.println("线程"+Thread.currentThread().getName()+"继续执行");
            catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        
         
        class MyThread extends Thread{
            @Override
            public void run() {
                System.out.println("进入线程"+Thread.currentThread().getName());
                try {
                    Thread.currentThread().sleep(5000);
                catch (InterruptedException e) {
                    // TODO: handle exception
                }
                System.out.println("线程"+Thread.currentThread().getName()+"执行完毕");
            }
        }
    }

    结果:Thread-0调用完毕后才继续执行main线程

    wait方法会让线程进入阻塞状态,并且会释放线程占有的锁,并交出CPU执行权限。

    由于wait方法会让线程释放对象锁,所以join方法同样会让线程释放对一个对象持有的锁。具体的wait方法使用在后面文章中给出。

      6)interrupt方法

      interrupt,顾名思义,即中断的意思。单独调用interrupt方法可以使得处于阻塞状态的线程抛出一个异常,也就说,它可以用来中断一个正处于阻塞状态的线程;另外,通过interrupt方法和isInterrupted()方法来停止正在运行的线程。

      下面看一个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class Test {
         
        public static void main(String[] args) throws IOException  {
            Test test = new Test();
            MyThread thread = test.new MyThread();
            thread.start();
            try {
                Thread.currentThread().sleep(2000);
            catch (InterruptedException e) {
                 
            }
            thread.interrupt();
        
         
        class MyThread extends Thread{
            @Override
            public void run() {
                try {
                    System.out.println("进入睡眠状态");
                    Thread.currentThread().sleep(10000);
                    System.out.println("睡眠完毕");
                catch (InterruptedException e) {
                    System.out.println("得到中断异常");
                }
                System.out.println("run方法执行完毕");
            }
        }
    }

       输出结果:

      

      从这里可以看出,通过interrupt方法可以中断处于阻塞状态的线程。那么能不能中断处于非阻塞状态的线程呢?看下面这个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class Test {
         
        public static void main(String[] args) throws IOException  {
            Test test = new Test();
            MyThread thread = test.new MyThread();
            thread.start();
            try {
                Thread.currentThread().sleep(2000);
            catch (InterruptedException e) {
                 
            }
            thread.interrupt();
        
         
        class MyThread extends Thread{
            @Override
            public void run() {
                int i = 0;
                while(i<Integer.MAX_VALUE){
                    System.out.println(i+" while循环");
                    i++;
                }
            }
        }
    }

       运行该程序会发现,while循环会一直运行直到变量i的值超出Integer.MAX_VALUE。所以说直接调用interrupt方法不能中断正在运行中的线程。

      但是如果配合isInterrupted()能够中断正在运行的线程,因为调用interrupt方法相当于将中断标志位置为true,那么可以通过调用isInterrupted()判断中断标志是否被置位来中断线程的执行。比如下面这段代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class Test {
         
        public static void main(String[] args) throws IOException  {
            Test test = new Test();
            MyThread thread = test.new MyThread();
            thread.start();
            try {
                Thread.currentThread().sleep(2000);
            catch (InterruptedException e) {
                 
            }
            thread.interrupt();
        
         
        class MyThread extends Thread{
            @Override
            public void run() {
                int i = 0;
                while(!isInterrupted() && i<Integer.MAX_VALUE){
                    System.out.println(i+" while循环");
                    i++;
                }
            }
        }
    }

       运行会发现,打印若干个值之后,while循环就停止打印了。

      但是一般情况下不建议通过这种方式来中断线程,一般会在MyThread类中增加一个属性 isStop来标志是否结束while循环,然后再在while循环中判断isStop的值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class MyThread extends Thread{
            private volatile boolean isStop = false;
            @Override
            public void run() {
                int i = 0;
                while(!isStop){
                    i++;
                }
            }
             
            public void setStop(boolean stop){
                this.isStop = stop;
            }
        }

       那么就可以在外面通过调用setStop方法来终止while循环。

      7)stop方法

      stop方法已经是一个废弃的方法,它是一个不安全的方法。因为调用stop方法会直接终止run方法的调用,并且会抛出一个ThreadDeath错误,如果线程持有某个对象锁的话,会完全释放锁,导致对象状态不一致。所以stop方法基本是不会被用到的。

      8)destroy方法

      destroy方法也是废弃的方法。基本不会被使用到。

      以下是关系到线程属性的几个方法:

      1)getId

      用来得到线程ID

      2)getName和setName

      用来得到或者设置线程名称。

      3)getPriority和setPriority

      用来获取和设置线程优先级。

      4)setDaemon和isDaemon

      用来设置线程是否成为守护线程和判断线程是否是守护线程。

      守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。

      Thread类有一个比较常用的静态方法currentThread()用来获取当前线程。

      在上面已经说到了Thread类中的大部分方法,那么Thread类中的方法调用到底会引起线程状态发生怎样的变化呢?下面一幅图就是在上面的图上进行改进而来的:

    展开全文
  • C++多线程(一)thread

    万次阅读 多人点赞 2018-04-10 16:28:29
    thread&gt;,&lt;mutex&gt;,&lt;condition_variable&gt;和&lt;future&gt;。 &lt;atomic&gt;:该头文主要声明了两个类, std::atomic 和 std::atomic_flag...

    与 C++11 多线程相关的头文件地方

    C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是<atomic> ,<thread>,<mutex>,<condition_variable>和<future>。

    <atomic>:该头文主要声明了两个类, std::atomic 和 std::atomic_flag,另外还声明了一套 C 风格的原子类型和与 C 兼容的原子操作的函数。
    <thread>:该头文件主要声明了 std::thread 类,另外 std::this_thread 命名空间也在该头文件中。
    <mutex>:该头文件主要声明了与互斥量(mutex)相关的类,包括 std::mutex 系列类,std::lock_guard, std::unique_lock, 以及其他的类型和函数。
    <condition_variable>:该头文件主要声明了与条件变量相关的类,包括 std::condition_variable 和 std::condition_variable_any。
    <future>:该头文件主要声明了 std::promise, std::package_task 两个 Provider 类,以及 std::future 和 std::shared_future 两个 Future 类,另外还有一些与之相关的类型和函数,std::async() 函数就声明在此头文件中。

    #include <iostream>  
    #include <thread>  
    
    using namespace std;  
    
    void th_function()  
    {  
        std::cout << "hello thread." << std::endl;  
    }  
    
    int main(int argc, char *argv[])  
    {  
        std::thread t(th_function);  
        t.join();  
    
        return 0;  
    }  

    这里写图片描述
    这里写图片描述

    std::thread 构造

    (1). 默认构造函数,创建一个空的 thread 执行对象。
    (2). 初始化构造函数,创建一个 thread对象,该 thread对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
    (3). 拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
    (4). move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。
    注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached.
    看一个例子:
    这个例子中创建了两个线程,其中一个线程函数带参数,大家仔细分析上面的thread类的构函数,看如何创建线程。

    // thread example  
    #include <iostream>       // std::cout  
    #include <thread>         // std::thread  
    
    void thr_function1()  
    {  
        for (int i = 0; i != 10; ++i)  
        {  
            std::cout << "thread 1 print " << i << std::endl;  
        }  
    }  
    
    void thr_function2(int n)  
    {  
        std::cout << "thread 1 print " << n << std::endl;  
    }  
    
    int main()  
    {  
        std::thread t1(thr_function1);     // spawn new thread that calls foo()  
        std::thread t2(thr_function2, 111);  // spawn new thread that calls bar(0)  
    
        std::cout << "main, foo and bar now execute concurrently...\n";  
    
        // synchronize threads:  
        t1.join();                // pauses until first finishes  
        t2.join();               // pauses until second finishes  
    
        std::cout << "thread 1 and htread 2 completed.\n";  
    
        return 0;  
    }  

    这里写图片描述
    大家的输出可能不是这样,有可能是下面这样的,不要紧,因为这个例子中没使用多线程的异步机制,线程之间存在竞争,看稍后文章讲解所以输出可能是下面这样的情况。
    这里写图片描述

    三、move 赋值操作

    move (1)    
    thread& operator= (thread&& rhs) noexcept;
    
    
    copy [deleted] (2)  
    thread& operator= (const thread&) = delete;

    (1). move 赋值操作,如果当前对象不可 joinable,需要传递一个右值引用(rhs)给 move 赋值操作;如果当前对象可被 joinable,则 terminate() 报错。
    (2). 拷贝赋值操作被禁用,thread 对象不可被拷贝。
    看下面的例子。

    // example for thread::operator=  
    #include <iostream>       // std::cout  
    #include <thread>         // std::thread, std::this_thread::sleep_for  
    #include <chrono>         // std::chrono::seconds  
    
    void pause_thread(int n)  
    {  
        std::this_thread::sleep_for(std::chrono::seconds(n));//c++11 this_thread 类  
        std::cout << "pause of " << n << " seconds ended\n";  
    }  
    
    int main()  
    {  
        std::thread threads[5];                         // default-constructed threads  
    
        std::cout << "Spawning 5 threads...\n";  
        for (int i = 0; i<5; ++i)  
            threads[i] = std::thread(pause_thread, i + 1);   // move-assign threads 这里调用move复制函数  
    
        std::cout << "Done spawning threads. Now waiting for them to join:\n";  
        for (int i = 0; i<5; ++i)  
            threads[i].join();  
    
        std::cout << "All threads joined!\n";  
    
        return 0;  
    }

    这里写图片描述

    1、成员类型和成员函数。
    2、std::thread 构造函数。
    3、异步。
    4、多线程传递参数。
    5、join、detach。
    6、获取CPU核心个数。
    7、CPP原子变量与线程安全。
    8、lambda与多线程。
    9、时间等待相关问题。
    10、线程功能拓展。
    11、多线程可变参数。
    12、线程交换。
    13、线程移动。

    1、成员类型和成员函数。

    这里写图片描述

    2、std::thread 构造函数。

    这里写图片描述
    (1).默认构造函数,创建一个空的 thread 执行对象。
    (2).初始化构造函数,创建一个 thread 对象,该 thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
    (3).拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
    (4).move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。
    注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached。

    #include<thread>  
    #include<chrono>  
    using namespace std;  
    void fun1(int n)  //初始化构造函数  
    {  
        cout << "Thread " << n << " executing\n";  
        n += 10;  
        this_thread::sleep_for(chrono::milliseconds(10));  
    }  
    void fun2(int & n) //拷贝构造函数  
    {  
        cout << "Thread " << n << " executing\n";  
        n += 20;  
        this_thread::sleep_for(chrono::milliseconds(10));  
    }  
    int main()  
    {  
        int n = 0;  
        thread t1;               //t1不是一个thread  
        thread t2(fun1, n + 1);  //按照值传递  
        t2.join();  
        cout << "n=" << n << '\n';  
        n = 10;  
        thread t3(fun2, ref(n)); //引用  
        thread t4(move(t3));     //t4执行t3,t3不是thread  
        t4.join();  
        cout << "n=" << n << '\n';  
        return 0;  
    }  
    运行结果:  
    Thread 1 executing  
    n=0  
    Thread 10 executing  
    n=30

    3、异步

    #include<thread>  
    using namespace std;  
    void show()  
    {  
        cout << "hello cplusplus!" << endl;  
    }  
    int main()  
    {  
        //栈上  
        thread t1(show);   //根据函数初始化执行  
        thread t2(show);  
        thread t3(show);  
        //线程数组  
        thread th[3]{thread(show), thread(show), thread(show)};   
        //堆上  
        thread *pt1(new thread(show));  
        thread *pt2(new thread(show));  
        thread *pt3(new thread(show));  
        //线程指针数组  
        thread *pth(new thread[3]{thread(show), thread(show), thread(show)});  
        return 0;  
    }

    4、多线程传递参数

    #include<thread>  
    using namespace std;  
    void show(const char *str, const int id)  
    {  
        cout << "线程 " << id + 1 << " :" << str << endl;  
    }  
    int main()  
    {  
        thread t1(show, "hello cplusplus!", 0);  
        thread t2(show, "你好,C++!", 1);  
        thread t3(show, "hello!", 2);  
        return 0;  
    }  
    运行结果:  
    线程 1线程 2 :你好,C++!线程 3 :hello!  
    :hello cplusplus!

    5、join、detach

    #include<thread>  
    #include<array>  
    using namespace std;  
    void show()  
    {  
        cout << "hello cplusplus!" << endl;  
    }  
    int main()  
    {  
        array<thread, 3>  threads = { thread(show), thread(show), thread(show) };  
        for (int i = 0; i < 3; i++)  
        {  
            cout << threads[i].joinable() << endl;//判断线程是否可以join  
            threads[i].join();//主线程等待当前线程执行完成再退出  
        }  
        return 0;  
    }  
    运行结果:  
    hello cplusplus!  
    hello cplusplus!  
    1  
    hello cplusplus!  
    1  
    1

    总结:
    join 是让当前主线程等待所有的子线程执行完,才能退出。
    detach例子如下:

    #include<thread>  
    using namespace std;  
    void show()  
    {  
        cout << "hello cplusplus!" << endl;  
    }  
    int main()  
    {  
        thread th(show);  
        //th.join();   
        th.detach();//脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。  
        //detach以后,子线程会成为孤儿线程,线程之间将无法通信。  
        cout << th.joinable() << endl;  
        return 0;  
    }  
    运行结果:  
    hello cplusplus! 

    结论:
    线程 detach 脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。
    线程 detach以后,子线程会成为孤儿线程,线程之间将无法通信。

    6、获取CPU核心个数。

    例如:

    #include<thread>  
    using namespace std;  
    int main()  
    {  
        auto n = thread::hardware_concurrency();//获取cpu核心个数  
        cout << n << endl;  
        return 0;  
    }  
    运行结果:  
    8

    结论:
    通过 thread::hardware_concurrency() 获取 CPU 核心的个数。

    7、CPP原子变量与线程安全

    问题例如:

    **#include<thread>  
    using namespace std;  
    const int N = 100000000;  
    int num = 0;  
    void run()  
    {  
        for (int i = 0; i < N; i++)  
        {  
            num++;  
        }  
    }  
    int main()  
    {  
        clock_t start = clock();  
        thread t1(run);  
        thread t2(run);  
        t1.join();  
        t2.join();  
        clock_t end = clock();  
        cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
        return 0;  
    }  
    运行结果:  
    num=143653419,用时 730 ms

    从上述代码执行的结果,发现结果并不是我们预计的200000000,这是由于线程之间发生冲突,从而导致结果不正确。
    为了解决此问题,有以下方法:
    (1)互斥量。
    例如:

    #include<thread>  
    #include<mutex>  
    using namespace std;  
    const int N = 100000000;  
    int num(0);  
    mutex m;  
    void run()  
    {  
        for (int i = 0; i < N; i++)  
        {  
            m.lock();  
            num++;  
            m.unlock();  
        }  
    }  
    int main()  
    {  
        clock_t start = clock();  
        thread t1(run);  
        thread t2(run);  
        t1.join();  
        t2.join();  
        clock_t end = clock();  
        cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
        return 0;  
    }  
    运行结果:  
    num=200000000,用时 128323 ms

    不难发现,通过互斥量后运算结果正确,但是计算速度很慢,原因主要是互斥量加解锁需要时间。
    互斥量详细内容 请参考下篇文章C++11 并发之std::mutex。
    (2)原子变量。
    例如:

    #include<thread>  
    #include<atomic>  
    using namespace std;  
    const int N = 100000000;  
    atomic_int num{ 0 };//不会发生线程冲突,线程安全  
    void run()  
    {  
        for (int i = 0; i < N; i++)  
        {  
            num++;  
        }  
    }  
    int main()  
    {  
        clock_t start = clock();  
        thread t1(run);  
        thread t2(run);  
        t1.join();  
        t2.join();  
        clock_t end = clock();  
        cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
        return 0;  
    }  
    运行结果:  
    num=200000000,用时 29732 ms

    不难发现,通过原子变量后运算结果正确,计算速度一般。
    原子变量详细内容 请参考C++11 并发之std::atomic。
    (3)加入 join 。
    例如:

    #include<thread>  
    using namespace std;  
    const int N = 100000000;  
    int num = 0;  
    void run()  
    {  
        for (int i = 0; i < N; i++)  
        {  
            num++;  
        }  
    }  
    int main()  
    {  
        clock_t start = clock();  
        thread t1(run);  
        t1.join();  
        thread t2(run);  
        t2.join();  
        clock_t end = clock();  
        cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
        return 0;  
    }  
    运行结果:  
    num=200000000,用时 626 ms

    不难发现,通过原子变量后运算结果正确,计算速度也很理想。

    8、lambda与多线程。
    例如:

    #include<thread>  
    using namespace std;  
    int main()  
    {  
        auto fun = [](const char *str) {cout << str << endl; };  
        thread t1(fun, "hello world!");  
        thread t2(fun, "hello beijing!");  
        return 0;  
    }  
    运行结果:  
    hello world!  
    hello beijing

    9、时间等待相关问题。
    例如:

    #include<thread>  
    #include<chrono>  
    using namespace std;  
    int main()  
    {  
        thread th1([]()  
        {  
            //让线程等待3秒  
            this_thread::sleep_for(chrono::seconds(3));  
            //让cpu执行其他空闲的线程  
            this_thread::yield();  
            //线程id  
            cout << this_thread::get_id() << endl;  
        });  
        return 0;  
    }

    10、线程功能拓展。

    例如:

    #include<thread>  
    using namespace std;  
    class MyThread :public thread   //继承thread  
    {  
    public:  
        //子类MyThread()继承thread()的构造函数  
        MyThread() : thread()  
        {  
        }  
        //MyThread()初始化构造函数  
        template<typename T, typename...Args>  
        MyThread(T&&func, Args&&...args) : thread(forward<T>(func), forward<Args>(args)...)  
        {  
        }  
        void showcmd(const char *str)  //运行system  
        {  
            system(str);  
        }  
    };  
    int main()  
    {  
        MyThread th1([]()  
        {  
            cout << "hello" << endl;  
        });  
        th1.showcmd("calc"); //运行calc  
        //lambda  
        MyThread th2([](const char * str)  
        {  
            cout << "hello" << str << endl;  
        }, " this is MyThread");  
        th2.showcmd("notepad");//运行notepad  
        return 0;  
    }  
    运行结果:  
    hello  
    //运行calc  
    hello this is MyThread  
    //运行notepad

    11、多线程可变参数

    例如:

    #include<thread>  
    #include<cstdarg>  
    using namespace std;  
    int show(const char *fun, ...)  
    {  
        va_list ap;//指针  
        va_start(ap, fun);//开始  
        vprintf(fun, ap);//调用  
        va_end(ap);  
        return 0;  
    }  
    int main()  
    {  
        thread t1(show, "%s    %d    %c    %f", "hello world!", 100, 'A', 3.14159);  
        return 0;  
    }  
    运行结果:  
    hello world!    100    A    3.14159

    12、线程交换。
    例如:

    #include<thread>  
    using namespace std;  
    int main()  
    {  
        thread t1([]()  
        {  
            cout << "thread1" << endl;  
        });  
        thread t2([]()  
        {  
            cout << "thread2" << endl;  
        });  
        cout << "thread1' id is " << t1.get_id() << endl;  
        cout << "thread2' id is " << t2.get_id() << endl;  
    
        cout << "swap after:" << endl;  
        swap(t1, t2);//线程交换  
        cout << "thread1' id is " << t1.get_id() << endl;  
        cout << "thread2' id is " << t2.get_id() << endl;  
        return 0;  
    }  
    运行结果:  
    thread1  
    thread2  
    thread1' id is 4836  
    thread2' id is 4724  
    swap after:  
    thread1' id is 4724  
    thread2' id is 4836

    两个线程通过 swap 进行交换。

    13、线程移动

    例如:

    #include<thread>  
    using namespace std;  
    int main()  
    {  
        thread t1([]()  
        {  
            cout << "thread1" << endl;  
        });  
        cout << "thread1' id is " << t1.get_id() << endl;  
        thread t2 = move(t1);;  
        cout << "thread2' id is " << t2.get_id() << endl;  
        return 0;  
    }  
    运行结果:  
    thread1  
    thread1' id is 5620  
    thread2' id is 5620

    从上述代码中,线程t2可以通过 move 移动 t1 来获取 t1 的全部属性,而 t1 却销毁了。

    展开全文
  • JAVA线程之Thread类详解

    万次阅读 多人点赞 2018-05-30 16:22:23
  • c/c++ __thread

    千次阅读 2018-09-10 23:30:18
    1. __thread 关键字表示每一个线程有一份独立的实体,每一个线程都不会干扰。 2. __thread 只能修饰POD变量,简单的来说可以是如下几种变量 (1) 基本类型 (int , float 等等) (2)指针类型 (3) 不带自定义构造...
  • __thread

    千次阅读 2018-07-21 16:31:12
    __thread是GCC内置的线程局部存储设施,存取效率可以和全局变量相比。__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。 ...
  • Thread(一)

    2019-09-30 23:07:47
    1. 核心概念 1.线程就是独立的执行路径。 2.在程序运行时,即使没有自己创建线程,后台也会存在多个线程,如垃圾回收线程,主线程。 3.在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器...
  • __thread关键字

    万次阅读 2013-11-03 09:04:29
    __thread是GCC内置的线程局部存储设施,存取效率可以和全局变量相比。__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。 ...
  • 【多线程】Thread和Runnable区别

    千次阅读 多人点赞 2019-06-17 15:13:43
    实现方式Thread类 线程?  线程是进程中独立运行的子任务,比如我们运行的QQMuic.exe的时候,然后就会有很多的子任务,而且不同的子任务可以共同工作,这时候每一个子任务就是一个线程,多个子任务共同工作,就是多...
  • Java Thread.join()详解

    万次阅读 多人点赞 2016-08-17 10:32:22
    Thread t = new AThread(); t.start(); t.join(); 二、为什么要用join()方法 在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理...
  • 深挖ThreadLocal

    万次阅读 多人点赞 2014-04-22 16:59:27
    ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocalThreadLocal为解决多线程程序的并发问题提供了一种新的思路。...其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它
  • 讲完了Thread以及ThreadGroup,接下来进行对ThreadLocal的认识。 文章目录1. 认识ThreadLocal2. ThreadLocal原理2.1 ThreadLocal.set2.2 ThreadLocal.get2.3 原理总结3. ThreadLocal OOM 1. 认识ThreadLocal 基于JDK8...
  • 每个ThreadLocal实例都有一个唯一的threadLocalHashCode(这个值将会用于在ThreadLocalMap中找到ThreadLocal对应的value值),它是通过静态变量nextHashCode和HASH_INCREMENT进行计算的,其中nextHashCode 和HASH_...
  • ThreadLocal、ThreadLocalMap、Thread详细解析
  • -- 最近再探Spring,深入研究了一下Spring的Introduce Advice。其中涉及到了关于ThreadLocal的一些内容,回顾了一下,这里做个记录。...-- Thread中维护了一个ThreadLocal.ThreadLocalMap的变量。 [code="ja...
  • package hub; /*为啥不同线程中的ThreadLocal是互相独立的。 明明是同一个thread对象 ...上面这个代码明明是一个thread对象,怎么打印出来的threadlocal的值不一样,也就是代表不是同一个threadlocal
  • 什么叫线程范围内的共享数据(线程外独立)? 一个线程在运行的时候可以调用A模块,B模块,C模块,就比如我们调用A,B,C三个对象,A,B,C三个模块内部的代码就要访问外面的变量,那么此时如果我们把ABC调用的那个...
  • 刚看了一下ThreadLocal的源码,刚开始一直看不懂为什么ThreadLocalMap中要定义一个Entry。 最初的理解是只需要在ThreadLocalMap中定义一个Object类型的成员变量就可以了,直到看到网上看到有博主在手机上画的一幅...
  • Thread public class Thread implements Runnable线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。 每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。 创建新执行线程有...

空空如也

1 2 3 4 5 ... 20
收藏数 1,651,502
精华内容 660,600
关键字:

thread