`
zoutuo1986
  • 浏览: 179665 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

线程相关,看到一半,任务来了,下次再看

 
阅读更多

copy :http://blog.csdn.net/MyTroy/article/details/38360495

 

一、Java线程状态

start之后是进去就绪状态,等待CPU的调度,而不是立即进去运行状态。当run函数返回,线程就终止了。

 

二、Thread.sleep

谁调用Thread.sleep方法谁休息,自己进入阻塞状态。Thread.sleep方法属于线程自己控制自己的状态。如果线程在sleep之前拥有某个对象的锁,则它在sleep的时候还会抱着这把锁不放。

 

三、obj.interrupt

obj是线程对象,其它线程调用obj的interrupt方法,将会打断obj线程的睡眠,引发obj线程的异常。

obj.stop,其它线程调用obj的stop方法可以让obj线程直接退出,粗暴直接,不要轻易使用(可能会导致某些打开的资源来不及关闭线程就退出了)。

 

四、join合并线程

Thread t1=new Thread(Runnable r);

t1.start();

t1.join();      //当前线程阻塞在此处

正在执行的线程调用t1的join方法将会合并t1线程,即相当于当前线程在方法调用(当前线程阻塞),直到等到t1线程执行完毕,当前线程才会继续执行。

yield:当前在执行的线程让出一次CPU时间给其它线程执行,自己立即进入就绪状态,等待CPU的再次调用。

(Thread.yield()谁调用此方法谁就让出CPU时间,但并不能保证让出后其它线程可以抢占到CPU时间。)
threadObj.setDaemon()方法将该线程标记为守护线程或用户线程,当正在运行的线程都是守护线程时,JVM会退出(该方法必须在线程启动前调用)。

 

五、synchronized互斥锁

每个对象只有一把锁(每一个对象对应一把锁),多个线程获取同一把锁时才会产生互斥效果,多个线程获取不同的锁时不会产生互斥效果。synchronized互斥锁锁住的是对象而不是代码。

 

同步方法和同步代码块synchronized(this){  //……  }效果一样,锁住的都是类的实例,同一时刻对于每一个类实例,其所有声明为synchronized的同步方法或被synchronized(this){  //……  }锁定的代码块至多只有一个处于可执行状态(因为同一时刻至多只有一个线程可获得该实例对应的锁),所有没有锁定的方法或代码块均可被多个线程同时执行。
同步代码块synchronized(obj){  //……  }锁定obj对象时,同一时刻对于每一个锁定的obj的同步代码块至多只有一个处于可执行状态(obj对象的锁只有一把,同一时刻只有一个线程可以获得该对象的锁),所有没有处于synchronized(obj){  //……  }同步代码块的代码均可被多个线程同时执行。
注意:
(1)同步代码块的锁的对象可以是任意的对象,包括this对象。
(2)同步方法锁的对象是this对象
(3)静态同步方法锁定的对象是类的字节码文件对象(ClassName.class)。因为静态方法中没有类的实例(this),所以不可能是this对象。

 

 

 

六、死锁

所谓死锁: 是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称程序处于死锁状态或程序产生了死锁,这些永远在互相等待的线程称为死锁线程。 由于资源占用是互斥的,当某个线程锁住某个资源后,使得有关线程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象:死锁。

假设有两个线程a和b,线程a和b结束的条件是分别同时锁住obj1和obj2对象,如果a已经获取到了obj1的锁正在努力获取obj2的锁但是obj2的锁已经被b获取,同时b也正在努力获取obj1的锁,因为只有线程结束才能释放锁,而正常结束的条件是一个线程必须同时获取到两个锁,因此a和b都得不到另外一个锁都无法结束,陷入了永久的等待状态,此时程序产生死锁。

死锁程序例如:

 

[java] view plaincopy
 
  1. import java.util.logging.Level;   
  2. import java.util.logging.Logger;  
  3.   
  4. public class DiedSynchronized {  
  5.     public static void main(String[] args) {  
  6.         Tellme m=new Tellme();  
  7.         Thread t1=new Thread(m,"t1");  
  8.         Thread t2=new Thread(m,"t2");  
  9.         System.out.println(Thread.currentThread().getName()+":t1和t2线程已经启动……");  
  10.         t1.start();  
  11.         t2.start();  
  12.         try {  
  13.             Thread.sleep((long)10000);  
  14.         } catch (InterruptedException ex) { }  
  15.         if(t1.isAlive() && t2.isAlive()) {  
  16.             System.out.println(Thread.currentThread().getName()+":10s内,t1和t2线程均没有正常结束,证明t1和t2线程死锁!");  
  17.             System.exit(0);  
  18.         }  
  19.         else  
  20.             System.out.println(Thread.currentThread().getName()+":t1和t2线程已经结束,证明没有死锁!");  
  21.     }  
  22. }  
[java] view plaincopy
 
  1. class Tellme implements Runnable {  
  2.     private Integer _number = new Integer(100);  
  3.     public boolean _flag = true;  
  4.     public void run() {  
  5.         if(_flag) {  
  6.             _flag=false;  
  7.             synchronized(this) {  
  8.                 System.out.println(Thread.currentThread().getName()+":已经获取到this锁,正在获取Number锁……");  
  9.                 try {  
  10.                     Thread.sleep((long)1000);  
  11.                 } catch (InterruptedException ex) { }  
  12.                 synchronized(_number) {  
  13.                     System.out.println(Thread.currentThread().getName()+":this锁和Number锁同时获取完毕!");  
  14.                 }  
  15.             }  
  16.         }else {  
  17.             synchronized(_number) {  
  18.                 System.out.println(Thread.currentThread().getName()+":已经获取到Number锁,正在获取this锁……");  
  19.                 try {  
  20.                     Thread.sleep((long)1000);  
  21.                 } catch (InterruptedException ex) { }  
  22.                 synchronized(this) {  
  23.                     System.out.println(Thread.currentThread().getName()+":this锁和Number锁同时获取完毕!");  
  24.                 }  
  25.             }  
  26.         }  
  27.     }  
  28. }  

 

 

运行结果如下:

 

run:
main:t1和t2线程已经启动……
t2:已经获取到Number锁,正在获取this锁……
t1:已经获取到this锁,正在获取Number锁……
main:10s内,t1和t2线程均没有正常结束,证明t1和t2线程死锁!
成功构建 (总时间: 10 秒)

 

t1和t2线程分别拥有this锁和Number锁,同时努力获取对方的锁,造成最终谁也得不到,程序进入死锁状态。Thread.sleep((long)1000)只是起放大作用,即使没有睡眠1秒程序也有可能进入死锁状态。

 

七、wait、notify、notifyAll

线程可以在任意对象的监视器(锁)上阻塞(wait,前提是获取到该对象的锁),也可以在唤醒任意一个wait在某个对象的监视器上的线程(notify,前提是获取到该对象的锁)。“获取到某个对象的锁”,就像获取到某种资格一样,只有有了这种资格才能够让自己阻塞在该锁上面或者唤醒已经阻塞在该锁上的其它线程。由此可知,每个对象的监视器上面自愿wait和被notify的线程只和该对象有关。因为每个对象都具有锁,每个锁均不同,故wait和notify的方法调用要通过对象调用,所以wait和notify方法要在Object中声明。

 

由于线程在任意对象的监视器都可以wait自己和notify其它线程,因此用Obj表示任意对象中的某个确定的对象,也包括this对象。线程调用Obj.wait(让自己wait在Obj的监视器上)和Obj.notify(唤醒任意一个已经wait在Obj的监视器上的线程)方法的前提是:已经获取到了Obj对象的锁,即Obj.wait()和Obj.notify()应该放在synchronize(Obj){ }代码块的内部。如果没有获取到Obj对象的锁,就没有这种“资格”执行这样的操作。
方法介绍:
wait:让自己在Obj对象的监视器上(锁)等待。获得Obj锁的线程调用Obj.wait()方法将使本线程放弃Obj的锁进入等待阻塞状态(wait在Obj对象的监视器上),直到另一个获得Obj锁的线程调用notify()或者notifyAll()方法才能唤醒此线程,等到此线程再次获取到Obj锁方可从暂停处继续执行。
notify:获得Obj锁的线程调用Obj.notify()方法将随机唤醒一个wait在Obj监视器上的线程,本线程并不会立即释放锁而是等待同步代码块执行完毕后再释放Obj锁。
notifyAll:唤醒所有正在wait在Obj监视器上的线程。
sleep和wait的区别
sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定。好比如说,我要做的事情是 "点火->烧水->煮面",而当我点完火之后我不立即烧水,我要休息一段时间再烧。对于运行的主动权是由我的流程来控制。而wait(),这是由某个确定的对象来调用的,将这个对象理解成一个传话的人,当这个人在某个线程里面说"暂停!",也是 thisOBJ.wait(),这里的暂停是阻塞,还是"点火->烧水->煮饭",thisOBJ就好比一个监督我的人站在我旁边,本来该线程应该执行1后执行2,再执行3,而在2处被那个对象喊暂停,那么我就会一直等在这里而不执行3,但这个流程并没有结束,我一直想去煮饭,但还没被允许,直到那个对象在某个地方说"通知暂停的线程启动!",也就是thisOBJ.notify()的时候,那么我就可以煮饭了,这个被暂停的线程就会从暂停处继续执行。
生产者和消费者例子:
本例子使用的篮子对象的锁(在篮子内部为this锁),该锁为生产者和消费者共同竞争。

 

 

[java] view plaincopy
 
  1. import java.util.Random;   
  2. import java.util.logging.Level;  
  3. import java.util.logging.Logger;  
  4. /** 
  5.  * Producer_Customer Program for testing wait_notify_notifyAll 
  6.  * 
  7.  * @author 忘川 
  8.  */  
  9. public class Producer_Customer {  
  10.     public static void main(String[] args) {  
  11.         Basket basket = new Basket();  
  12.         Producer pro = new Producer(basket);  
  13.         Customer cus = new Customer(basket);  
  14.          
  15.         Thread proth1 = new Thread(pro, "一");  
  16.         Thread proth2 = new Thread(pro, "二");  
  17.         Thread proth3 = new Thread(pro, "三");  
  18.         Thread proth4 = new Thread(pro, "四");  
  19.         Thread custh1 = new Thread(cus, "custh1");  
  20.         Thread custh2 = new Thread(cus, "custh2");  
  21.          
  22.         proth1.start();  
  23.         proth2.start();  
  24.         proth3.start();  
  25.         proth4.start();  
  26.         custh1.start();  
  27.         custh2.start();  
  28.     }  
  29. }  
[java] view plaincopy
 
  1. class Producer implements Runnable {  
  2.     private Basket basket = null;  
  3.     public Producer(Basket basket) {  
  4.         this.basket = basket;  
  5.     }  
  6.     public void run() {  
  7.         Random r = new Random();  
  8.         for (int i = 0; i < 4; i++) {  
  9.             basket.put(new Apple(Thread.currentThread().getName() + "#" + i));  
  10.             try {  
  11.                 Thread.sleep((long) r.nextDouble() * 1000);  
  12.             } catch (InterruptedException ex) { }  
  13.         }  
  14.     }  
  15. }  
 
[java] view plaincopy
 
  1. class Customer implements Runnable {  
  2.     private Basket basket = null;  
  3.     public Customer(Basket basket) {  
  4.         this.basket = basket;  
  5.     }  
  6.     public void run() {  
  7.         Random r = new Random();  
  8.         for (int i = 0; i < 8; i++) {  
  9.             basket.eat();  
  10.             try {  
  11.                 Thread.sleep((long) r.nextDouble() * 1000);  
  12.             } catch (InterruptedException ex) { }  
  13.         }  
  14.     }  
  15. }  
 
[java] view plaincopy
 
  1. class Basket {  
  2.     private Apple[] basket = new Apple[3];  
  3.     private int index = 0;  
  4.     public synchronized void put(Apple a) {  
  5.         while (index == 2) {  
  6.             try {  
  7.                 this.wait();  
  8.             } catch (InterruptedException ex) { }  
  9.         }  
  10.         this.notifyAll();  
  11.         basket[index++] = a;  
  12.         System.out.println("生产:" + a + " 篮子剩余=" + index);  
  13.     }  
  14.     public synchronized void eat() {  
  15.         while (index == 0) {  
  16.             try {  
  17.                 this.wait();  
  18.             } catch (InterruptedException ex) { }  
  19.         }  
  20.         this.notifyAll();  
  21.         System.out.println("吃掉:" + basket[--index] + " 篮子剩余=" + index);  
  22.     }  
  23. }  
 
[java] view plaincopy
 
  1. class Apple {  
  2.     public String ID;  
  3.     public Apple(String id) {  
  4.         this.ID = id;  
  5.     }  
  6.     public String toString() {  
  7.         return ID;  
  8.     }  
  9. }  

 

 

其中的一个运行结果如下:

 

run:
生产:三#0 篮子剩余=1
生产:四#0 篮子剩余=2
生产:一#0 篮子剩余=3
吃掉:一#0 篮子剩余=2
生产:二#0 篮子剩余=3
吃掉:二#0 篮子剩余=2
生产:三#1 篮子剩余=3
吃掉:三#1 篮子剩余=2
生产:一#1 篮子剩余=3
吃掉:一#1 篮子剩余=2
生产:一#2 篮子剩余=3
吃掉:一#2 篮子剩余=2
吃掉:四#0 篮子剩余=1
生产:二#1 篮子剩余=2
生产:三#2 篮子剩余=3
吃掉:三#2 篮子剩余=2
生产:二#2 篮子剩余=3
吃掉:二#2 篮子剩余=2
生产:二#3 篮子剩余=3
吃掉:二#3 篮子剩余=2
生产:三#3 篮子剩余=3
吃掉:三#3 篮子剩余=2
吃掉:二#1 篮子剩余=1
生产:四#1 篮子剩余=2
生产:一#3 篮子剩余=3
吃掉:一#3 篮子剩余=2
生产:四#2 篮子剩余=3
吃掉:四#2 篮子剩余=2
生产:四#3 篮子剩余=3
吃掉:四#3 篮子剩余=2
吃掉:四#1 篮子剩余=1
吃掉:三#0 篮子剩余=0
成功构建 (总时间: 0 秒)

从运行结果可以看出,每当篮子中苹果个数达到3个(篮子所能容纳的上线时),生产者线程就自愿wait在篮子的监视器上,转而让消费者线程先消费之后再唤醒生产者线程;每当篮子中的苹果个数为0时,消费者线程就会自愿wait在篮子的监视器上,转而让生产者线程先生产之后再唤醒消费者线程。篮子就像一个控制中心,生产过剩,生产线程就资源wait,转而让消费线程消费;反之亦然。

 

分享到:
评论

相关推荐

    Java多线程之定时任务 以及 SpringBoot多线程实现定时任务——异步任务

    1. SpringBoot 自定义线程池以及多线程间的异步调用(@Async、@EnableAsync) 2.Java多线程之定时任务 以及 SpringBoot多线程实现定时任务 3.@EnableScheduling 与 @Scheduled

    基于任务线程处理例子

    总之,基于任务的线程处理是Java并发编程的重要组成部分,理解并熟练掌握线程、任务、队列以及相关的调度工具,能帮助开发者编写出更高效、更稳定的并发程序。通过实践和学习提供的代码示例,你可以更好地理解这些...

    易语言源码多线程多任务下载软件.rar

    《易语言源码多线程多任务下载软件》是一款基于易语言编程的高效下载工具,其核心特性在于利用多线程技术实现多个文件的同时下载,提高下载效率,满足用户快速批量下载的需求。本文将深入探讨易语言编程环境、多线程...

    多线程多任务下载软件.zip易语言项目例子源码下载

    在这个“多线程多任务下载软件.zip”压缩包中,包含的是一个易语言项目的源码,可以作为学习和参考的实例。下面将详细解释多线程和多任务下载的概念,以及如何在易语言中实现这些功能。 1. **多线程技术**:在...

    易语言多线程执行任务例程

    在易语言中,我们可以通过创建线程对象并调用其相关函数来实现这一功能。 1. **线程创建与启动**:在易语言中,创建线程通常涉及到“创建线程”和“启动线程”两个步骤。首先,我们需要定义一个子程序,这个子程序...

    定时任务启动多线线程示例

    在Java开发中,Spring框架是广泛使用的,它不仅提供了丰富的功能,还支持诸如定时任务和多线程等高级特性。本示例将深入探讨如何在Spring框架中利用定时任务(Spring Task)启动多线程来执行并发操作。 首先,我们...

    第二章多任务和多线程 第二章多任务和多线程

    第二章多任务和多线程第二章多任务和多线程第二章多任务和多线程第二章多任务和多线程第二章多任务和多线程第二章多任务和多线程第二章多任务和多线程第二章多任务和多线程第二章多任务和多线程第二章多任务和多线程...

    多线程并发执行任务

    本文将深入探讨多线程并发执行任务的相关知识点,并基于提供的`MyThread.java`文件,来分析和理解如何在Java中实现多线程。 首先,我们需要了解什么是线程。线程是操作系统分配处理器时间的基本单元,一个进程可以...

    Qt 之多线程处理多任务

    线程池是一种线程管理机制,它预先创建一组线程,当有任务需要执行时,线程池会自动分配一个空闲线程来执行任务,完成后再返回线程池。这种方式减少了线程创建和销毁的开销,提高了程序的运行效率。`QThreadPool`类...

    12.如何实现多线程多任务?(Visual C++编程 源代码)

    12.如何实现多线程多任务?(Visual C++编程 源代码)12.如何实现多线程多任务?(Visual C++编程 源代码)12.如何实现多线程多任务?(Visual C++编程 源代码)12.如何实现多线程多任务?(Visual C++编程 源代码)...

    winform 多线程 多任务管理

    在本文中,我们将深入探讨如何在Winform应用程序中实现多线程和多任务管理,这对于提高应用程序的性能和响应性至关重要,特别是处理耗时操作时。 首先,了解多线程的概念是必要的。在单线程应用程序中,所有任务都...

    多线程实现任务管理器

    在.NET框架中,`System.Threading`命名空间提供了线程相关的类,如`Thread`、`ThreadPool`和`Task`等。`Thread`类是线程的基本表示,可以创建新的线程实例来执行特定的代码块。然而,直接使用`Thread`对象创建大量...

    多线程任务控制实例代码

    主要实现了,多个线程任务在同时执行的情况下,保证线程任务顺序的问题。更通俗来说,就是保证Thread1一定在thread2,thread3之后才能执行。另外,代码里我写了详细的注释,和测试的效果,绝对让你能看懂。还有我传的...

    操作系统课程设计--基于线程的多任务系统实现

    在WIN-TC下的基于线程的多任务系统实现

    多线程执行任务具体实现

    在计算机科学中,多线程是一种程序设计技术,它允许应用程序同时执行多个不同的任务或子任务,从而提高系统的效率和响应速度。多线程在Java、C++、Python等编程语言中都有广泛的应用。本篇文章将深入探讨多线程执行...

    qt利用线程实现多任务下载

    Qt是一个跨平台的C++库,提供了丰富的功能,包括对多线程的支持,这使得开发人员可以利用多线程来实现并发任务,如多任务下载。本示例"qt利用线程实现多任务下载"就是一个很好的实践,它不仅展示了Qt的多线程技术,...

    易语言多线程任务分配模块源码

    在易语言中,多线程任务分配模块是实现并发处理的关键组件,尤其适用于处理耗时操作或者提高程序执行效率。本模块的源码提供了一个简单而实用的多线程解决方案。 首先,我们要理解什么是多线程。在计算机科学中,...

    多任务多线程下载器源码

    标题中的“多任务多线程下载器源码”是指一个软件程序,它的功能是同时处理多个下载任务,并且每个任务都是在独立的线程中运行。这种设计模式提高了下载效率,因为不同任务可以在CPU的不同核心上并发执行,避免了单...

    Java多线程机制(讲述java里面与多线程有关的函数)

    Java多线程机制是Java编程中至关重要的一部分,它允许程序同时执行多个任务,提升应用程序的效率和响应性。以下是对各个知识点的详细说明: 9.1 Java中的线程: Java程序中的线程是在操作系统级别的线程基础上进行...

    线程的监控任务demo

    5. **日志与调试**:为了分析线程的行为,开发者通常会记录线程相关的日志信息,包括线程ID、执行时间、状态变化等。这些信息在调试和性能优化时非常有用。 6. **事件驱动**:某些监控任务可能基于事件触发,例如,...

Global site tag (gtag.js) - Google Analytics