JAVA多线程编程实例详解

本文实例讲述了JAVA多线程编程。分享给大家供大家参考,具体如下:

  • 进程是系统进行资源调度和分配的一个独立单位。
  • 进程的特点
    独立性:进程是系统中独立存在的实体,拥有自己的独立资源和私有空间。在没有经过进程本身允许的情况下,不能直接访问其他进程。
    动态性:进程与程序的区别在于,前者是一个正在系统中活动的指令,而后者仅仅是一个静态的指令集合
    并发性:多个进程可以在单个处理器上并发执行,而不受影响。

并发性和并行性的区别:
并行性:在同一时刻,有多条指令在多个处理器上同时执行(多个CPU)
并发性:在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得宏观上具有多个进程同时执行的效果(单核)。

  • 通过继承Thread类来创建并启动多线程
public class Deom_1 extends Thread{

  public void run(){
      super.run();
      System.out.println("MyThread01");
    }

  public static void main(String[] args){
    Deom_1 demo=new Deom_1();
    demo.setName("Demo_1");
    demo.start();
    System.out.println("当前线程的名字:"+Thread.currentThread().getName()+" 运行结束");
  }
}

多次调用start会抛出java.lang.IllegalThreadStateException异常
如果只调用run(),不调用start()方法,就相当于调用了一个普通的函数,实际上还是在同一个线程中运行的run()方法。

  • 多线程编程时不要忘记了Java程序运行时默认的主线程,main方法的方法体就是主线程的线程执行体
  • 使用继承Thread类的方法来创建线程类,多条线程之间无法共享线程的实例变量
  • 实现Runnable接口创建线程类
//通过实现Runnable接口来创建线程类
public class SecondThread implements Runnable
{
  private int i ;
  //run方法同样是线程执行体
  public void run()
  {
    for ( ; i < 20 ; i++ )
    {
      //当线程类实现Runnable接口时,
      //如果想获取当前线程,只能用Thread.currentThread()方法。
      System.out.println(Thread.currentThread().getName() + " " + i);
    }
  }

  public static void main(String[] args)
  {
    for (int i = 0; i < 50; i++)
    {
      System.out.println(Thread.currentThread().getName() + " " + i);
      if (i == 20)
      {
        SecondThread st = new SecondThread();
        //通过new Thread(target , name)方法创建新线程
        new Thread(st , "新线程1").start();
        new Thread(st , "新线程2").start();
      }
    }
  }
}
  • 采用实现继承方式的多线程:
    编程相对简单
    多条线程之间无法共享线程类实例变量
    继承Thread类之后就不能继承其他的父类
  • 采用实现接口的方式的多线程:
    线程类只是实现了Runnable接口,还可以继承其他类
    在这种方式下,可以多个线程共享同一个对象,非常适合多个相同线程来处理同一份资源的情况。
    编程稍稍复杂一点
  • 线程的生命周期:新建(NEW)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、死亡(Dead)
  • 当程序使用new关键字创建一个线程后,该线程就处于新建状态;当线程对象调用了start()方法之后,该线程就处于就绪状态;如果处于就绪状态的线程获得了CPU,开始执行run方法的线程执行体,则该线程就处于运行状态;但是它不可能一直处于运行状态,可能会被中断进入阻塞状态;线程运行结束后就会进入到死亡状态。
  • 线程进入阻塞状态的情况:
    线程调用了sleep方法主动放弃所占有的资源
    线程调用了一个阻塞式IO方法,在该方法返回的时候被阻塞
    线程尝试获取一个同步监听器,但是被其他线程占有
    在等待某个通知
    调用线程suspend方法挂起,不推荐使用容易造成死锁。
  • 线程进入就绪状态的情况:
    调用sleep方法的线程经过了指定时间
    线程调用的阻塞式IO方法已经返回
    线程成功获取试图取得同步监听器
    线程在等待某个通知,其他线程发出一个通知
    处于挂起状态的线程调用了resume恢复方法

进入阻塞状态的线程在获得执行机会后重新进入就绪状态,而不是运行状态

  • 线程进入死亡状态的情况:
    run()方法执行完成,线程正常结束
    线程抛出一个未捕获的异常或者错误
    直接调用该线程的stop方法来结束该线程——该方法容易导致死锁,通常不推荐。

当主线程结束的时候,其他线程不受影响。一旦子线程启动它就拥有和主线程一样的地位。

  • 不要试图对一个已经死亡的线程调用start()方法使它重新启动,会抛出IllegalThreadStateException异常。调用线程的isAlive()方法可以测试某条线程是否死亡。
  • JAVA中控制线程的方法:
    join线程
    后台线程
    线程睡眠:sleep
    线程让步:yield
    改变线程优先级
  • join线程
    join():等待被join的线程执行完成
    join(long millis):等待被join的线程时间最长millis毫秒
    join(long millis, int nanos):等待被join的线程的时间最长millis毫秒加上nanos微秒
  • 后台线程:任务是给其他线程提供服务,成为“后台线程”、“守候线程”。如果说有的前台线程死亡,后台线程会自动死亡。

调用Thread类的setDaemon(true)方法可以将指定线程设置为后台线程。该方法一定要在启动线程之前设置,否则会发生异常。同时提供isDaemon()方法判断是否是后台线程。主线程一般默认为前台线程前台线程创建的子线程默认是前台,后台线程创建的子线程默认是后台。

  • 改变线程的优先级
PriorityTest low = new PriorityTest("低级");
low.start();
System.out.println("创建之初的优先级:" + low.getPriority());
//设置该线程为最低优先级
low.setPriority(Thread.MIN_PRIORITY);
PriorityTest high = new PriorityTest("高级");
high.start();
System.out.println("创建之初的优先级:" + high.getPriority());
//设置该线程为最高优先级
high.setPriority(Thread.MAX_PRIORITY);

每个线程的默认优先级都与创建它的父线程具有相同的线程,在默认的情况下,main线程具有普通优先级。

  • 线程让步
    yield()方法是Thread提供的一个静态方法,可以让当前正在执行的线程暂停转入就绪状态。等待下一次的重新调度。
    实际上,当某个线程调用了yield()方法后只有优先级相同或者高于当前线程的其他就绪状态的线程才会获得执行的机会。
  • sleep和yield方法的区别
    1、sleep方法暂停当前线程后,会给其他线程机会执行,不会理会其他线程的优先级。但是yield方法只会给优先级相同或者更高的线程
    2、sleep方法会将线程转入阻塞状态,直到经过阻塞时间才会转入就绪状态。而yield方法直接转入就绪状态
    3、sleep方法会抛出InterruptedException异常,所以调用时需要显示捕获异常,yield方法不会抛出任何异常
    4、sleep方法比yield方法具有更多的移植性,通常不依靠yield方法控制并发线程执行。
  • 如果多个线程共同访问1个对象中的实例变量,则有可能出现”非线程安全”
class SelfPrivateNum {
  private int num = 0;

  public void addI(String username) {
    try {

      if (username.equals("a")) {
        num = 100;
        System.out.println("a set over!");
        Thread.sleep(2000);
      } else {
        num = 200;
        System.out.println("b set over!");
      }
      System.out.println(username + " num=" + num);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

}

class ThreadAA extends Thread {

  private SelfPrivateNum numRef;

  public ThreadAA(SelfPrivateNum numRef) {
    super();
    this.numRef = numRef;
  }

  @Override
  public void run() {
    super.run();
    numRef.addI("a");
  }

}

class ThreadBB extends Thread {

  private SelfPrivateNum numRef;

  public ThreadBB(SelfPrivateNum numRef) {
    super();
    this.numRef = numRef;
  }

  @Override
  public void run() {
    super.run();
    numRef.addI("b");
  }

}

public class RunUnsafe {

  public static void main(String[] args) {

    SelfPrivateNum numRef = new SelfPrivateNum();

    ThreadAA athread = new ThreadAA(numRef);
    athread.start();

    ThreadBB bthread = new ThreadBB(numRef);
    bthread.start();

  }

}
  • 同步方法:就是使用synchronized关键字来修饰某个方法。当多个线程调用这个方法的时,以排队的方式进行处理。同步方法不具有继承性
class SelfPrivateNum2 {
  private int num = 0;

  public synchronized void addI(String username) {
    try {

      if (username.equals("a")) {
        num = 100;
        System.out.println("a set over!");
        Thread.sleep(2000);
      } else {
        num = 200;
        System.out.println("b set over!");
      }
      System.out.println(username + " num=" + num);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

}

关键字synchronized取的是锁都是对象锁,而不是代码或者是方法当作锁。当多个线程访问的是同一个对象的同步方法的时候是排队的,而当多个线程访问多个对象的同步方法的时候运行的顺序是异步的。

  • A线程先持有object对象的锁,B线程可以以异步的方式调用object对象总的非synchronizaed类型的方法
  • A线程先持有object对象的锁,B线程如果调用object的synchronizaed类型的方法则需要等待,也就是同步。
  • 脏读

为了避免数据出现交叉的情况,使用synchronized关键字来进行同步。虽然在赋值时进行了同步,但是可能在取值的时候出现脏读(dirtyRead)的现象。发生脏读的情况是在读取实例变量时。出现脏读是应为getValue方法不是同步方法,解决方法可以定义为同步方法。

  • synchronized方法是对当前对象进行加锁,而synchronized代码块是对某一个对象进行加锁。
//线程开始执行同步代码块之前,必须先获得对同步监控器的锁定
synchronized (Obj){
  ………
  //此处的代码就是同步代码块
}

通常使用可能被并发访问的共享资源充当同步监视器。

  • 对同步监视器释放的情况:
    当前线程的同步方法或代码块执行结束
    当前线程的同步方法或代码块中遇到break、return终止了该代码块、方法的继续执行
    当前线程的同步方法或代码块中出现未处理的Error或Exception
    当前线程的同步方法或代码块中执行了同步监控器对象的wait()方法
  • 以下情况不会释放同步锁:
    当前线程的同步方法或代码块调用 Thread.sleep(),Thread.yield()方法来暂停当前线程执行
    当前线程的同步方法或代码块时,其他线程调用了该线程的suspend方法让该线程挂起
  • LOCK锁
Class A{
   private final ReentrantLock lock= new ReentrantLock ();
   //需要保证线程安全的方法
   public void m(){
    //加锁
    lock.lock();
    try{
      ……………
    }
    finally{
     lock.unlock();
    }
  }
}   

同步方法的比较
1、同步方法和同步代码块使用与竞争资源相关的、隐式的同步监视器,并且强制要求加锁和释放锁要出现在同一个块结构中,而且当获取多个锁的时候,他们必须按照相反的顺序依次释放。
2、Lock方法不仅可以使用与非结构快中,还可以试图中断锁和再次加锁的功能。被Lock加锁的代码中还可以嵌套调用。
3、资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍。

  • Volatile关键字
    强制性从公共堆栈中(存放实例)中取得修饰的变量的值,而不是从线程的私有数据栈中取得变量的值。不能保证不会出现脏读的情况,需要用关键字synchronized来解决。
  • ThreadLocal类
    ThreadLocal在每个线程中对该变量会创建一个副本,即每个线程内部都会有一个该变量,且在线程内部任何地方都可以使用,线程之间互不影响。ThreadLocal提供资源的共享对象!
    T get():返回此线程局部变量中当前线程副本的值
    void remove():删除此线程局部变量中当前副本的值
    void set(T value):设置此线程局部变量中当前线程副本的值

如果需要进行多个线程之间共享资源,以达到线程之间的通信功能,就使用同步机制;如果仅仅需要隔离多个线程之间的共享冲突,可以使Threadlocal。

  • 死锁:当两个线程相互等待对象释放同步监视器的时候就会发生死锁。

    使用一种称为资源排序的简单技术可以轻易避免死锁。

  • 等待通知机制

方法wait()的作用是使当前执行代码线程进行等待,是Object类的方法,该方法用来将当前线程置于“阻塞队列”中,并在wait()所在的代码处停止执行,直到接到通知被唤醒。

在调用wait()之前,线程必须持有该对象的对象级别锁,只能在同步方法或者是同步块中调用此方法。在执行wait方法后,当前线程释放锁。进入和其他线程竞争重新获得锁。如果调用wait方法没有持有锁,则会抛出异常。

方法notify()用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随便选择一个呈wait状态的线程。

方法nofity()也是在同步方法或者同步块中调用,调用前同样要获得对象的对象级别所,否则抛出异常。在执行notify方法后,当前线程不会马上释放该对象锁,要等到执行notify方法的线程将程序执行完才能会释放锁。

方法notifyAll()方法可以使正在等待队列中等待同一共享资源的”全部”线程从等待状态退出,进入可运行状态。

public class Test3 {
  //main方法中有三个等待线程,一个唤醒线程,一个唤醒线程只能唤醒一个等待线程,程序出现阻塞
  public static void main(String[] args) throws InterruptedException {

    Object lock = new Object();

    ThreadA a = new ThreadA(lock);
    new ThreadA(lock).start();
    new ThreadA(lock).start();
    new ThreadA(lock).start();

    Thread.sleep(1000);

    NotifyThread notifyThread = new NotifyThread(lock);
    notifyThread.start();

  }

}

class ThreadA extends Thread {
  private Object lock;

  public ThreadA(Object lock) {
    super();
    this.lock = lock;
  }

  @Override
  public void run() {
    Service service = new Service();
    service.testMethod(lock);
  }

}

class NotifyThread extends Thread {
  private Object lock;

  public NotifyThread(Object lock) {
    super();
    this.lock = lock;
  }

  @Override
  public void run() {
    synchronized (lock) {
      //notify()只能唤醒一个线程,nofiyAll()唤醒所有的等待线程
      lock.notify();
//     lock.notifyAll();
    }
  }

}

class Service {

  public void testMethod(Object lock) {
    try {
      synchronized (lock) {
        System.out.println("begin wait() ThreadName="
            + Thread.currentThread().getName());
        lock.wait();
        System.out.println(" end wait() ThreadName="
            + Thread.currentThread().getName());
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

}
  • 使用条件变量协调线程

在没有使用synchronized关键字保证同步,而采用Lock的程序。Java提供了condition类来保持协调。Lock替代synchronized,Condition替代同步监视器功能。
await: 类似于wait。
signal:唤醒在此Lock对象上等待的单个线程,选择是任意的。
signalAll:唤醒在此Lock对象上等待的所有线程,选择是任意的。

public class Account
{
  //显示定义Lock对象
  private final Lock lock = new ReentrantLock();
  //获得指定Lock对象对应的条件变量
  private final Condition cond = lock.newCondition(); 

  private String accountNo;
  private double balance;

  //标识账户中是否已经存款的旗标
  private boolean flag = false;

  public Account(){}

  public Account(String accountNo , double balance)
  {
    this.accountNo = accountNo;
    this.balance = balance;
  }

  public void setAccountNo(String accountNo)
  {
    this.accountNo = accountNo;
  }
  public String getAccountNo()
  {
     return this.accountNo;
  }

  public double getBalance()
  {
     return this.balance;
  }
  public void draw(double drawAmount)
  {
    //加锁
    lock.lock();
    try
    {
      //如果账户中还没有存入存款,该线程等待
      while(!flag)
      {
        cond.await();
      }
        //执行取钱操作
        System.out.println(Thread.currentThread().getName() +
          " 取钱:" + drawAmount);
        balance -= drawAmount;
        System.out.println("账户余额为:" + balance);
        //将标识是否成功存入存款的旗标设为false
        flag = false;
        //唤醒该Lock对象对应的其他线程
        cond.signalAll();
    }
    catch (InterruptedException ex)
    {
      ex.printStackTrace();
    }
    //使用finally块来确保释放锁
    finally
    {
      lock.unlock();
    }
  }
  public void deposit(double depositAmount)
  {
    lock.lock();
    try
    {
      //如果账户中已经存入了存款,该线程等待
      while(flag)
      {
        cond.await();
      }

        //执行存款操作
        System.out.println(Thread.currentThread().getName() +
          " 存款:" + depositAmount);
        balance += depositAmount;
        System.out.println("账户余额为:" + balance);
        //将标识是否成功存入存款的旗标设为true
        flag = true;
        //唤醒该Lock对象对应的其他线程
        cond.signalAll();
    }
    catch (InterruptedException ex)
    {
      ex.printStackTrace();
    }
    //使用finally块来确保释放锁
    finally
    {
      lock.unlock();
    }
  }

  public int hashCode()
  {
    return accountNo.hashCode();
  }
  public boolean equals(Object obj)
  {
    if (obj != null && obj.getClass() == Account.class)
    {
      Account target = (Account)obj;
      return target.getAccountNo().equals(accountNo);
    }
    return false;
  }
}

使用notify()/notifyAll()方法进行通知时,被通知的线程却是JVM随机选择的。当notifyAll()通知所有WAITING线程,没有选择权,会出现相当大的效率问题。但是ReentrantLock结合Condition类可以”选择性通知”。Condition可以实现唤醒部分指定线程,这样有助于程序运行的效率。

  • Callable和Future

从JDK1.5之后,Java提供了Callable接口,实际上就是Runnable接口的增强版。提供call方法作为线程执行体,但是功能更加强大。
Callable接口不是Runnable接口,不能直接作为Thread的target,有返回值得call方法也不能直接运行。这里需要一个包装器Future。

import java.util.concurrent.*;

class RtnThread implements Callable<Integer>
{
  //实现call方法,作为线程执行体
  public Integer call()
  {
    int sum = 0;
    int i=0;
    for ( ; i < 10 ; i++ )
    {
      System.out.println(Thread.currentThread().getName()+ " 的循环变量i的值:" + i);
      sum+=i;
    }
    //call()方法可以有返回值

    return sum;
  }
} 

public class CallableTest
{
  public static void main(String[] args)
  {
    //创建Callable对象
    RtnThread rt = new RtnThread();
    //使用FutureTask来包装Callable对象
    FutureTask<Integer> task = new FutureTask<Integer>(rt);
    for (int i = 0 ; i < 10 ; i++)
    {
      System.out.println(Thread.currentThread().getName()
        + " 的循环变量i的值:" + i);
      if (i == 5)
      {
        //实质还是以Callable对象来创建、并启动线程
        new Thread(task , "有返回值的线程").start();
      }
    }
    try
    {
      //获取线程返回值
      System.out.println("子线程的返回值:" + task.get());
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
  }
}
  • 线程池
import java.util.concurrent.*;

//实现Runnable接口来定义一个简单的
class TestThread implements Runnable
{
  public void run()
  {
    for (int i = 0; i < 10 ; i++ )
    {
      System.out.println(Thread.currentThread().getName()
        + "的i值为:" + i);
    }
  }
}

public class ThreadPoolTest
{
  public static void main(String[] args)
  {
    //创建一个具有固定线程数(6)的线程池
    ExecutorService pool = Executors.newFixedThreadPool(6);
    //向线程池中提交3个线程
    pool.execute(new TestThread());
    Future f1=pool.submit(new TestThread());
    Future f2=pool.submit(new TestThread());

    Future<Integer> f3=pool.submit(new RtnThread());

    try
    {
      if(f1.get()==null&&f2.get()==null&&f3.get()!=null){
        System.out.println("执行完毕!");
        System.out.println(f3.get());

      }
      //获取线程返回值

    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
    //关闭线程池
    pool.shutdown();
  }
}

更多java相关内容感兴趣的读者可查看本站专题:《Java进程与线程操作技巧总结》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

时间: 2019-09-01

Java中对AtomicInteger和int值在多线程下递增操作的测试

Java针对多线程下的数值安全计数器设计了一些类,这些类叫做原子类,其中一部分如下: java.util.concurrent.atomic.AtomicBoolean; java.util.concurrent.atomic.AtomicInteger; java.util.concurrent.atomic.AtomicLong; java.util.concurrent.atomic.AtomicReference; 下面是一个对比  AtomicInteger 与 普通 int 值在多线

15个高级Java多线程面试题及回答

Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题.在投资银行业务中多线程和并发是一个非常受欢迎的话题,特别是电子交易发展方面相关的.他们会问面试者很多令人混淆的Java线程问题.面试官只是想确信面试者有足够的Java线程与并发方面的知识,因为候选人中有很多只浮于表面.用于直接面向市场交易的高容量和低延时的电子交易系统在本质上是并发的.下面这些是我在不同时间不同地点喜欢问的Jav

Java多线程实现异步调用的方法

在JAVA平台,实现异步调用的角色有如下三个角色:调用者 提货单   真实数据 一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单.然后在过一断时间后凭提货单来获取真正的数据. 去蛋糕店买蛋糕,不需要等蛋糕做出来(假设现做要很长时间),只需要领个提货单就可以了(去干别的事情),等到蛋糕做好了,再拿提货单取蛋糕就可以了. public class Main { public static void main(String[] args) { System.out.println("ma

详解三种java实现多线程的方式

java中实现多线程的方法有两种:继承Thread类和实现runnable接口. 1.继承Thread类,重写父类run()方法 public class thread1 extends Thread { public void run() { for (int i = 0; i < 10000; i++) { System.out.println("我是线程"+this.getId()); } } public static void main(String[] args) {

Java多线程之中断线程(Interrupt)的使用详解

interrupt方法 interrupt字面上是中断的意思,但在Java里Thread.interrupt()方法实际上通过某种方式通知线程,并不会直接中止该线程.具体做什么事情由写代码的人决定,通常我们会中止该线程. 如果线程在调用Object类的wait().wait(long)或wait(long, int)方法,或者该类的 join() .join(long) .join(long, int) .sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态

Java多线程的用法详解

1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( );  public Thread(Runnable target);  public Thread(String name);  public Thread(Runnable target

java基本教程之join方法详解 java多线程教程

本章涉及到的内容包括:1. join()介绍2. join()源码分析(基于JDK1.7.0_40)3. join()示例 1. join()介绍join() 定义在Thread.java中.join() 的作用:让"主线程"等待"子线程"结束之后才能继续运行.这句话可能有点晦涩,我们还是通过例子去理解: 复制代码 代码如下: // 主线程public class Father extends Thread {    public void run() {     

深入理解JAVA多线程之线程间的通信方式

一,介绍 本总结我对于JAVA多线程中线程之间的通信方式的理解,主要以代码结合文字的方式来讨论线程间的通信,故摘抄了书中的一些示例代码. 二,线程间的通信方式 ①同步 这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信. 参考示例: public class MyObject { synchronized public void methodA() { //do something.... } synchronized public void methodB()

Java多线程下载的实现方法

复制代码 代码如下: package cn.me.test; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; /** * 多线程下载 * 1:使用RandomAccessFile在任意的位置写入数据. * 2:需要计算第一个线程下载的数据量,可以平均分配.如果不够平均时, *    则直接最后一个线程处理相对较少

java多线程和并发包入门示例

一.java多线程基本入门java多线程编程还是比较重要的,在实际业务开发中经常要遇到这个问题. java多线程,传统创建线程的方式有两种. 1.继承自Thread类,覆写run方法. 2.实现Runnable接口,实现run方法. 启动线程的方法都是调用start方法,真正执行调用的是run方法.参考代码如下: 复制代码 代码如下: package com.jack.thread; /** * 线程简单演示例子程序 *  * @author pinefantasy * @since 2013-

java向多线程中传递参数的三种方法详细介绍

在传统的同步开发模式下,当我们调用一个函数时,通过这个函数的参数将数据传入,并通过这个函数的返回值来返回最终的计算结果.但在多线程的异步开发模式下,数据的传递和返回和同步开发模式有很大的区别.由于线程的运行和结束是不可预料的,因此,在传递和返回数据时就无法象函数一样通过函数参数和return语句来返回数据.本文就以上原因介绍了几种用于向线程传递数据的方法,在下一篇文章中将介绍从线程中返回数据的方法. 欲先取之,必先予之.一般在使用线程时都需要有一些初始化数据,然后线程利用这些数据进行加工处理,并

C# 写入XML文档三种方法详细介绍

我在以前的博客中介绍了如何使用XmlDocument类对XML进行操作,以及如何使用LINQ to XML对XML进行操作.它们分别使用了XmlDocument类和XDocument类.在本文中,我再介绍一个类,XmlTextWriter.我们分别用这三个类将同样的xml内容写入文档,看一看哪种写法最直观.简便. 我们要写入的XML文档内容为 复制代码 代码如下: <?xml version="1.0" encoding="UTF-8"?> <Co

详解向scrapy中的spider传递参数的几种方法(2种)

有时需要根据项目的实际需求向spider传递参数以控制spider的行为,比如说,根据用户提交的url来控制spider爬取的网站.在这种情况下,可以使用两种方法向spider传递参数. 第一种方法,在命令行用crawl控制spider爬取的时候,加上-a选项,例如: scrapy crawl myspider -a category=electronics 然后在spider里这样写: import scrapy class MySpider(scrapy.Spider): name = 'm

python解析命令行参数的三种方法详解

这篇文章主要介绍了python解析命令行参数的三种方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 python解析命令行参数主要有三种方法:sys.argv.argparse解析.getopt解析 方法一:sys.argv -- 命令行执行:python test_命令行传参.py 1,2,3 1000 # test_命令行传参.py import sys def para_input(): print(len(sys.argv)) #

Struts2获取参数的三种方法总结

Struts2获取参数的三种方法总结 前言: Struts2不在建议我们使用原生的servletAPI来获取参数,这样做的目的是事项Struts2的action与servlet进行解耦,可以在日后更加方便的对action类进行测试. Struts2获取参数的三种办法: (1)属性驱动方式 (2)模型驱动方式 (3)对象驱动方式 one by one 属性驱动方式 /* * 参数获取方式之属性驱动方式 */ public class TestAction extends ActionSupport

Java Spring Controller 获取请求参数的几种方法详解

Java Spring Controller 获取请求参数的几种方法  1.直接把表单的参数写在Controller相应的方法的形参中,适用于get方式提交,不适用于post方式提交.若"Content-Type"="application/x-www-form-urlencoded",可用post提交 url形式:http://localhost:8080/SSMDemo/demo/addUser1?username=lixiaoxi&password=1

关于C++中定义比较函数的三种方法小结

C++编程优与Pascal的原因之一是C++中存在STL(标准模板库).STL存在很多有用的方法. C++模板库中的许多方法都需要相关参数有序,例如Sort().显然,如果你想对一个集合进行排序,你必须要知道集合中的对象,那个在前那个在后.因此,学会如何定义比较方法是非常重要的. C++模板库的许多容器需要相关类型有序,例如set<T> 和priority_queue<T>. 这篇文章旨在告诉大家如何为一个类定义一个排序方法,以便在STL容器或者方法中使用. 作为一个C++程序员,

Android中使用定时器的三种方法

本文实例为大家分享了Android中使用定时器的三种方法,供大家参考,具体内容如下 图示: 因为都比较简单,所以就直接贴代码(虑去再次点击停止的操作),有个全局的Handler负责接收消息更新UI 第一种方法:Thread.sleep();方法 Runnable runnable = new Runnable() { @Override public void run() { while (true) { mHandler.sendEmptyMessage(0); try { Thread.sl

Java去掉数字字符串开头的0三种方法(推荐)

方式一: 例如:"0000123" (字符串必须全为数字) 处理过程: String tempStr = "0000123"; int result = Integer.parseInt(tempStr); result 结果:123 方式二: 例如:"0000123" 处理过程: String str = "0000123"; String newStr = str.replaceFirst("^0*",

vue中锚点的三种方法

第一种: router.js中添加 mode: 'history', srcollBehavior(to,from,savedPosition){ if(to.hash){ return { selector:to.hash } } } 组件: <template> <div> <ul class="list"> <li><a href="#1" rel="external nofollow"