`

java多线程

阅读更多

java中常用的线程同步的函数:

sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行;

 

yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。


sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会。

 

调用join()的线程将使其执行完毕后,才执行其他线程。可以控制线程的执行保持特定的顺序。


waite() 和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生 IllegalMonitorStateException的异常。

 

用synchronized来修饰的函数或者程序块将只能允许一个线程访问。

 

三个经典例子:

1.生产者和消费者问题

 

class Resource{

     int id;

     public Resource(int id){

          this.id=id;

     }

     public String toString(){

         return "Resource:"+id;

     }

 

}

 

 

//临界数据操作类

class DataOpr{

 

    int index=0;

   

    //创建临界资源池

    Resource[] rsc=new Resource[10];

  

    //添加资源

    public synchronized void add(Resource r){
        try{
            while(index==rsc.length)){
                 this.wait();
            }
             this.notifyAll();
             rsc[index]=r;

             index++;
        }catch(Exception e){
             e.printStackTrace();
        }

    }

   

    //取出资源

    public synchronized Resource get(){
         try{
             while(index==0){
                  this.wait();
              }
              this.notifyAll();           
            
         }catch(Exception e){
              e.printStackTrace();
         }

         index--;
         return rsc[index];
    }

 

}

 

 

 

//生产者线程

class Producer implements Runnable{

     DataOpr dp=null;

     public Producer(DataOpr dp){

          this.dp=dp;

     }

     public void run(){

         for(int i=0;i<20;i++){

             Resource rsc=new Resource(i);

             dp.add(rsc);

             System.out.println("生产了"+rsc);

          }

 

     }

}

 

 

 

//消费者线程

 class Consumer implements Runnable{

      DataOpr dp=null;

      public Consumer(DataOpr dp){

            this.dp=dp;

      }

 

      public void run(){
          try{
           
             for(int i=0;i<20;i++){
                 Thread.sleep(200);
                 Resource rsc=dp.get();
                 System.out.println("消费了"+rsc);

            }
          }catch(Exception e){
               e.printStackTrace();
          }

 

      }

 

 }

 

 

 

class TestProCon{

 

    public static void main(String[] args){

        DataOpr dp=new DataOpr();


        Producer p=new Producer(dp);
        Consumer c=new Consumer(dp);

        Thread t1=new Thread(p);
        Thread t2=new Thread(c);

 

        t1.start();
        t2.start();

    

    }

 

}

 

 

 

 

 

2.死锁程序示例

 

//测试类
public class DeadLock{
 
 public static void main(String[] args){
  Resource1 r1=new Resource1();
   Resource2 r2=new Resource2();
  
   Visitor1 v1=new Visitor1(r1,r2);
   Visitor2 v2=new Visitor2(r1,r2);
  
   Thread t1=new Thread(v1);
   Thread t2=new Thread(v2);
  
   t1.start();
   t2.start();
 }
 
}


//临界资源1
class Resource1{
 
  int i=0;
 
  public  void visit(String visitor){
      System.out.println("Resource1"+visitor);
  }
 
}


//临界资源2
class Resource2{
 public  void visit(String visitor){
   System.out.println("Resource22"+visitor);
 }
 
}


//线程1
class Visitor1 implements Runnable{
    Resource1 r1;
    Resource2 r2;
    public Visitor1(Resource1 r1,Resource2 r2){
       this.r1=r1;
       this.r2=r2;
    }
 
    public void run(){
        synchronized(r1){
             r1.visit("visitor1");
             try{
                 Thread.sleep(2000);
             }catch(Exception e){
             }
             synchronized(r2){
                  r2.visit("visitor2");
             }
        } 
    }


 }
 

//线程2
class Visitor2 implements Runnable{
 Resource1 r1;
 Resource2 r2;
 public Visitor2(Resource1 r1,Resource2 r2){
  
  this.r1=r1;
  this.r2=r2;
 }
 
 public void run(){
      synchronized(r2){
           r1.visit("visitor2");
           try{
               Thread.sleep(2000);
           }catch(Exception e){
           }
           synchronized(r1){
                r2.visit("visitor1");
           }
       } 
   }

 
 }
 
 

 

3. 读者写着问题(读者优先)

//测试类

public class TReaderWriter{
  public static void main(String[] args){
       TLiberary lib=new TLiberary();
       TReader tr=new TReader (lib);
       TWriter tw=new TWriter(lib);
       Thread tt1=new Thread(tr);
       Thread tt2=new Thread(tr);
       Thread tt3=new Thread(tr);
       Thread tt4=new Thread(tr);
       Thread tt5=new Thread(tr);
       Thread tt6=new Thread(tw);
       Thread tt7=new Thread(tw);
       Thread tt8=new Thread(tw);
       tt1.start();
       tt2.start();
       tt3.start();
         tt4.start();
           tt5.start();
       tt6.start();
       tt7.start();
       tt8.start();
   }
}

 

//图书馆(临界资源类)

class TLiberary{

     int rCount;

     int wCount;

     public synchronized void read(){

         while(wCount>=1){
           
             try{
                this.wait();
             }catch(Exception e){
             }
        
          }

          this.notify();
          rCount++;

          System.out.println("reading...");

          try{

               Thread.sleep(1000);

          }catch(Exception e){

          }

          rCount--;

       

                              

     }

 

     public synchronized void write(){

          while(rCount>=1 && wCount==1){
               try{
                 this.wait();
               }catch(Exception e){
               }
          }

          this.notify();
          wCount++;

          System.out.println("writing...");

          try{

               Thread.sleep(1000);

          }catch(Exception e){

          }

          wCount--;

         

       

      }

}

 

//读者线程

class TReader implements Runnable{

     TLiberary lib;

   

     public TReader(TLiberary lib){

          this.lib=lib;

     }

    

     public void run(){     

          lib.read();

     }

         

 

}

 

//写者线程

class TWriter implements Runnable{

 

     TLiberary lib;

   

     public TWriter(TLiberary lib){

          this.lib=lib;

     }

    

     public void run(){     

          lib.write();

     }

         

 

}

 

 

相关面试题:

1、java 中有几种方法可以实现一个线程?用什么关键字修饰同步方法 ? stop() 和 suspend() 方 法为何不推荐使用?
答: 有两种实现方法,分别是继承 Thread类与实现Runnable接口
用synchronized关键字修饰同步方法
反 对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果 很难检查出真正的问题所在。suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此 时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就 会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用 wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。


2 、 sleep() 和 wait() 有什么区别 ?
答: sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。


3 、 请说出你所知道的线程同步的方法。
答: wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
notityAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

 

 

 

参考:http://wxg6203.iteye.com/blog/763488

概念:在一个程序中,这些独立运行的程序片断叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。

目的:多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。

线程的4个状态:

New(新建)线程对象仅仅是创建,并没有调用start()方法。

runnable(就绪)只要调度程序将时间片分配给线程,它便可以立刻运行

Blocked(阻塞)线程可以运行,但是由于某个条件阻止了它的运行。当线程为阻塞状态时,调度程序将不会将时间片分给它。

Dead(死亡)



注:线程进入阻塞的某些原因:1)sleep()方法,使线程进入休眠状态。2)wait()方法,使线程挂起。3)线程等待某个输入/输出的完成。4)线程试图调用某个对象上的同步控制方法,但是该对象锁不可用。5)suspend(),但是Java 2 中被废弃了。通常有3种可以恢复:sleep自动恢复、对于suspend调用resume恢复、对于wait可以用通知(notify或notiyA11)方法使其恢复。



实现方式:继承Thread类和实现Runnable接口重写run方法



线程的级别:

static int MAX_PRIORITY
线程可以具有的最高优先级。
static int MIN_PRIORITY
线程可以具有的最低优先级。
static int NORM_PRIORITY
分配给线程的默认优先级。

主要方法
void interrupt() //中断线程。
static boolean interrupted() //测试当前线程是否已经中断。
boolean isAlive()//测试线程是否处于活动状态。
boolean isDaemon() //测试该线程是否为守护线程。
boolean isInterrupted() //测试线程是否已经中断。
void join() //等待该线程终止。
run()//如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回
static void sleep(long millis)//在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
void start()// 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
void stop()// 过时
suspend()//已过时。
resume()// 已过时。
destroy()//已过时。
yield()//暂停当前正在执行的线程对象,并执行其他线程。

执行图





注意点:



sleep() 方法:sleep() 允许 指定以毫秒为单位的一段时间作为参数,它使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。可能给其他线程执行的机会(自私,睡着了,不释放锁,时间到了才放锁)



yield() 方法:yield() 使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。不过yield()只能使同等级别的线程获取执行的机会(公平竞争,释放大家再次选举)。而sleep(1000)使同级别或不同级别的都有可能。



wait() 和 notify() 和notifyAll()方法是Object中定义的方法:
必须在synchronized代码块中使用,在synchronized代码被执行期间,线程可以调用对象的wait()方法,释放对象的锁标志,进入等待的状态,并且可以调用notify()或者notifyAll()方法通知正在等待的其他线程。notify()通知的是等待队列中的第一个线程,notifyAll()通知的是等待队列中的所有数量。
几个方法配套使用,wait() 使得线程进入阻塞状态,它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用。



wait()和sleep()方法的区别:
wait()在object类里定义;sleep()在Thread类里定义。
wait()方法只能放在同步方法或同步块中,表示资源同步时,线程需要等待。
sleep()方法可放在任何位置,表示当前线程睡眠。
wait()方法会释放对象锁;sleep()不会释放对象锁。
wait()方法要等待唤醒之后,线程才会继续执行。
sleep()则是休眠一段时间,线程自动恢复执行.
sleep()必须捕获异常,而wait(),notify()和notifyAll()不需要捕获异常

notify()和notifyAll()的区别
notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的,我们无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。
notifyAll() 方法将把因调用该对象的 wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。



join()是直到执行完(或强制执行一段时间)当前的线程后才往下执行主线程或其他的线程

Java有两种Thread:“守护线程Daemon”与“用户线程User”。





用户线程:Java虚拟机在它所有非守护线程已经离开后自动离开。
守护线程:守护线程则是用来服务用户线程的,如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去。
setDaemon(boolean on)方法可以方便的设置线程的Daemon模式,true为Daemon模式,false为User模式。setDaemon(boolean on)方法必须在线程启动之前调用,当线程正在运行时调用会产生异常。isDaemon方法将测试该线程是否为守护线程。值得一提的是,当你在一个守护线程中产生了其他线程,那么这些新产生的线程不用设置Daemon属性,都将是守护线程,用户线程同样。



例:我们所熟悉的Java垃圾回收线程就是一个典型的守护线程,当我们的程序中不再有任何运行中的Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是Java虚拟机上仅剩的线程时,Java虚拟机会自动离开。



在守护线程中创建非守护线程(前提是非守护线程执行语句要放在守护线程前),则不会因为其他所有非守护线程的结束而程序运行结束。总之一句话,如果当前还有一个非守护线程在执行,则程序不会结束(不管他是不是在守护线程中创建)。因为在守护线程中创建的默认都是守护线程,当然如果把守护线程创建的默认守护线程改成非守护线程,运行结果就不一样了。而在非守护线程中创建守护线程就很好理解了。



同步:

同步有两种方法。一种同步方法,一种同步代码!分别是synchronized,wait与notify



注意:

同步和异步有何异同,在什么情况下分别使用他们?。
如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。





synchronized 和 java.util.concurrent.locks.Lock 的异同
主要相同点: Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。

 

分享到:
评论

相关推荐

    Java多线程知识点总结

    Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...

    java 多线程操作数据库

    ### Java多线程操作数据库:深入解析与应用 在当今高度并发的应用环境中,Java多线程技术被广泛应用于处理数据库操作,以提升系统的响应速度和处理能力。本文将基于一个具体的Java多线程操作数据库的应用程序,深入...

    Java多线程设计模式上传文件

    Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式...

    java多线程经典案例

    Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,极大地提升了程序的效率和性能。在Java中,实现多线程有两种主要方式:通过实现Runnable接口或者继承Thread类。本案例将深入探讨Java多线程中的关键...

    java多线程Demo

    Java多线程是Java编程中的一个重要概念,它允许程序同时执行多个任务,提高了程序的效率和响应速度。在Java中,实现多线程有两种主要方式:继承Thread类和实现Runnable接口。 1. 继承Thread类: 当我们创建一个新...

    java多线程的讲解和实战

    Java多线程是Java编程中的重要概念,尤其在如今的多核处理器环境下,理解并熟练掌握多线程技术对于提高程序性能和响应速度至关重要。本资料详细讲解了Java多线程的原理,并提供了丰富的实战代码,非常适合Java初学者...

    java多线程分页查询

    ### Java多线程分页查询知识点详解 #### 一、背景与需求分析 在实际的软件开发过程中,尤其是在处理大量数据时,如何高效地进行数据查询成为了一个关键问题。例如,在一个用户众多的社交平台上,当用户需要查看...

    汪文君JAVA多线程编程实战(完整不加密)

    《汪文君JAVA多线程编程实战》是一本专注于Java多线程编程的实战教程,由知名讲师汪文君倾力打造。这本书旨在帮助Java开发者深入理解和熟练掌握多线程编程技术,提升软件开发的效率和质量。在Java平台中,多线程是...

    java多线程ppt

    java多线程PPT 多线程基本概念 创建线程的方式 线程的挂起与唤醒 多线程问题

    java多线程读取文件

    Java多线程读大文件 java多线程写文件:多线程往队列中写入数据

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

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

    深入浅出 Java 多线程.pdf

    在本文中,我们将深入浅出Java多线程编程的世界,探索多线程编程的基本概念、多线程编程的优点、多线程编程的缺点、多线程编程的应用场景、多线程编程的实现方法等内容。 一、多线程编程的基本概念 多线程编程是指...

    java 多线程并发实例

    在Java编程中,多线程并发是提升程序执行效率、充分利用多核处理器资源的重要手段。本文将基于"java 多线程并发实例"这个主题,深入探讨Java中的多线程并发概念及其应用。 首先,我们要了解Java中的线程。线程是...

    java多线程实现大批量数据导入源码

    本项目以"java多线程实现大批量数据导入源码"为题,旨在通过多线程策略将大量数据切分,并进行并行处理,以提高数据处理速度。 首先,我们需要理解Java中的线程机制。Java通过`Thread`类来创建和管理线程。每个线程...

    JAVAJAVA多线程教学演示系统论文

    《JAVA多线程教学演示系统》是一篇深入探讨JAVA多线程编程的论文,它针对教育领域中的教学需求,提供了一种生动、直观的演示方式,帮助学生更好地理解和掌握多线程技术。这篇论文的核心内容可能包括以下几个方面: ...

    java多线程查询数据库

    综上所述,"java多线程查询数据库"是一个涉及多线程技术、线程池管理、并发控制、分页查询等多个方面的复杂问题。通过理解和掌握这些知识点,我们可以有效地提高数据库操作的效率和系统的响应速度。

    java 多线程编程实战指南(核心 + 设计模式 完整版)

    《Java多线程编程实战指南》这本书深入浅出地讲解了Java多线程的核心概念和实战技巧,分为核心篇和设计模式篇,旨在帮助开发者掌握并应用多线程技术。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程...

    JAVA多线程编程技术PDF

    这份“JAVA多线程编程技术PDF”是学习和掌握这一领域的经典资料,涵盖了多线程的全部知识点。 首先,多线程的核心概念包括线程的创建与启动。在Java中,可以通过实现Runnable接口或继承Thread类来创建线程。创建后...

    Java多线程编程核心技术_完整版_java_

    Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程主要通过继承Thread类或实现Runnable接口来实现。本教程《Java多线程编程核心技术》将...

    Java多线程编程实战指南-核心篇

    《Java多线程编程实战指南-核心篇》是一本深入探讨Java并发编程的书籍,旨在帮助读者掌握在Java环境中创建、管理和同步线程的核心技术。Java的多线程能力是其强大之处,使得开发者能够在同一时间执行多个任务,提高...

Global site tag (gtag.js) - Google Analytics