java的多线程用法编程总结

一、进程与线程

1、进程是什么?

狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。

广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

2、线程是什么?

线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

3、进程和线程的区别?

进程和线程的主要差别在于它们是不同的操作系统资源管理方式。

进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。

线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

简言之,线程与进程的区别就是:

(1)一个程序至少有一个进程,一个进程至少有一个线程;
(2) 线程的划分尺度小于进程,使得多线程程序的并发性高。
(3)进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
(4)线程在执行过程中与进程是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
(5)从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。

这就是进程和线程的重要区别。

二、线程的生命周期及五种基本状态

Java线程具有五种基本状态:

(1)新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

(2)就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

(3)运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

(4)阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

①等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

②同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

③其他阻塞 : 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

(5)死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

三、Java多线程的实现

在Java中,如果要实现多线程的程序,那么必须依靠一个线程的主体类(好比主类的概念一样,表示一个线程的主类),但是这个线程的主体类在定义的时候需要有一些特殊的要求,这个类可以继承Thread类或实现Runnable接口来完成定义。

1、继承Thread类实现多线程

java.lang.Thread是一个负责线程操作的类,任何的类继承了Thread类就可以成为一个线程的主类。既然是主类,必须有它的使用方法,而线程启动的主方法需要覆写Thread类中的run()方法才可以。

定义一个线程的主体类:

class MyThread extends Thread { // 线程的主体类
 private String title;

 public MyThread(String title) {
 this.title = title;
 }

 @Override
 public void run() { // 线程的主方法
 for (int x = 0; x < 10; x++) {
  System.out.println(this.title + "运行,x = " + x);
 }
 }
}

现在已经有了线程类,并且里面也存在了相应的操作方法,那么就应该产生对象并调用里面的方法,于是编写出了下的程序:

public class TestDemo {
 public static void main(String[] args) {
 MyThread mt1 = new MyThread("线程A");
 MyThread mt2 = new MyThread("线程B");
 MyThread mt3 = new MyThread("线程C");
 mt1.run();
 mt2.run();
 mt3.run();
 }

运行结果:

线程A运行,x = 0
线程A运行,x = 1
线程A运行,x = 2
线程A运行,x = 3
线程A运行,x = 4
线程A运行,x = 5
线程A运行,x = 6
线程A运行,x = 7
线程A运行,x = 8
线程A运行,x = 9
线程B运行,x = 0
线程B运行,x = 1
线程B运行,x = 2
线程B运行,x = 3
线程B运行,x = 4
线程B运行,x = 5
线程B运行,x = 6
线程B运行,x = 7
线程B运行,x = 8
线程B运行,x = 9
线程C运行,x = 0
线程C运行,x = 1
线程C运行,x = 2
线程C运行,x = 3
线程C运行,x = 4
线程C运行,x = 5
线程C运行,x = 6
线程C运行,x = 7
线程C运行,x = 8
线程C运行,x = 9

我们发现:以上的操作并没有真正的启动多线程,因为多个线程彼此之间的执行一定是交替的方式运行,而此时是顺序执行,每一个对象的代码执行完之后才向下继续执行。

如果要想在程序之中真正的启动多线程,必须依靠Thread类的一个方法:public void start(),表示真正启动多线程,调用此方法后会间接调用run()方法:

public class TestDemo {
 public static void main(String[] args) {
 MyThread mt1 = new MyThread("线程A");
 MyThread mt2 = new MyThread("线程B");
 MyThread mt3 = new MyThread("线程C");
 mt1.start();
 mt2.start();
 mt3.start();
 }

}

运行结果:

线程C运行,x = 0
线程A运行,x = 0
线程B运行,x = 0
线程A运行,x = 1
线程C运行,x = 1
线程A运行,x = 2
线程B运行,x = 1
线程A运行,x = 3
线程A运行,x = 4
线程A运行,x = 5
线程C运行,x = 2
线程C运行,x = 3
线程C运行,x = 4
线程C运行,x = 5
线程C运行,x = 6
线程C运行,x = 7
线程C运行,x = 8
线程C运行,x = 9
线程A运行,x = 6
线程A运行,x = 7
线程A运行,x = 8
线程A运行,x = 9
线程B运行,x = 2
线程B运行,x = 3
线程B运行,x = 4
线程B运行,x = 5
线程B运行,x = 6
线程B运行,x = 7
线程B运行,x = 8
线程B运行,x = 9

此时可以发现:多个线程之间彼此交替执行,但每次的执行结果是不一样的。通过以上的代码就可以得出结论:要想启动线程必须依靠Thread类的start()方法执行,线程启动之后会默认调用了run()方法。

在调用start()方法之后,发生了一系列复杂的事情:
(1)启动新的执行线程(具有新的调用栈);
(2)该线程从新状态转移到可运行状态;
(3)当该线程获得机会执行时,其目标run()方法将运行。
注意:对Java来说,run()方法没有任何特别之处。像main()方法一样,它只是新线程知道调用的方法名称(和签名)。因此,在Runnable上或者Thread上调用run方法是合法的,但并不启动新的线程。

说明:为什么线程启动的时候必须调用start()而不是直接调用run()?

我们发现,在调用了start()之后,实际上它执行的还是覆写后的run()方法,那为什么不直接调用run()方法呢?为了解释此问题,下面打开Thread类的源代码,观察一下start()方法的定义:

 public synchronized void start() {
 if (threadStatus != 0)
  throw new IllegalThreadStateException();
 group.add(this);
 boolean started = false;
 try {
  start0();
  started = true;
 } finally {
  try {
  if (!started) {
   group.threadStartFailed(this);
  }
  } catch (Throwable ignore) {
  }
 }
 }
 private native void start0();

打开此方法的源代码首先可以发现:方法会抛出一个“IllegalThreadStateException”异常。一般来讲,如果一个方法中使用了throw抛出一个异常对象,那么这个异常应该使用try…catch捕获,或者是方法的声明上使用throws抛出,但是这块都没有,为什么呢?因为这个异常类是属于运行时异常(RuntimeException)的子类:

java.lang.Object
   |- java.lang.Throwable
     |- java.lang.Exception
       |- java.lang.RuntimeException
         |- java.lang.IllegalArgumentException
           |- java.lang.IllegalThreadStateException

当一个线程对象被重复启动之后会抛出此异常,即:一个线程对象只能启动一次。

在start()方法之中有一个最为关键的部分就是start0()方法,而且这个方法上使用了一个native关键字的定义。

native关键字指的是Java本地接口调用(Java Native Interface),即:是使用Java调用本机操作系统的函数功能完成一些特殊的操作,而这样的代码开发在Java之中几乎很少出现,因为Java的最大特点是可移植性,如果一个程序只能在固定的操作系统上使用,那么可移植性就将彻底的丧失,所以,此操作一般不用。

多线程的实现一定需要操作系统的支持,那么以上的start0()方法实际上就和抽象方法很类似没有方法体,而这个方法体交给JVM去实现,即:在windows下的JVM可能使用A方法实现了start0(),而在Linux下的JVM可能使用了B方法实现了start0(),但是在调用的时候并不会去关心具体是何方式实现了start0()方法,只会关心最终的操作结果,交给JVM去匹配了不同的操作系统。

所以在多线程操作之中,使用start()方法启动多线程的操作是需要进行操作系统函数调用的。

2、实现Runnable接口实现多线程

使用Thread类的确是可以方便的进行多线程的实现,但是这种方式最大的缺点就是单继承的问题。为此,在java之中也可以利用Runnable接口来实现多线程。这个接口的定义如下:

public interface Runnable {
 public void run();
}

通过Runnable接口实现多线程:

class MyThread implements Runnable { // 线程的主体类
 private String title;

 public MyThread(String title) {
 this.title = title;
 }

 @Override
 public void run() { // 线程的主方法
 for (int x = 0; x < 10; x++) {
  System.out.println(this.title + "运行,x = " + x);
 }
 }
}

这和之前继承Thread类的方式区别不大,但是有一个优点就是避免了单继承局限。

不过问题来了。之前说过,如果要启动多线程,需要依靠Thread类的start()方法完成,之前继承Thread类的时候可以将此方法直接继承过来使用,但现在实现的是Runable接口,没有这个方法可以继承了,怎么办?

要解决这个问题,还是需要依靠Thread类完成。在Thread类中定义了一个构造方法,接收Runnable接口对象:

public Thread(Runnable target);

利用Thread类启动多线程:

public class TestDemo {
 public static void main(String[] args) throws Exception {
 MyThread mt1 = new MyThread("线程A");
 MyThread mt2 = new MyThread("线程B");
 MyThread mt3 = new MyThread("线程C");
 new Thread(mt1).start();
 new Thread(mt2).start();
 new Thread(mt3).start();
 }
}

运行结果:

线程A运行,x = 0
线程B运行,x = 0
线程B运行,x = 1
线程C运行,x = 0
线程B运行,x = 2
线程A运行,x = 1
线程B运行,x = 3
线程C运行,x = 1
线程C运行,x = 2
线程B运行,x = 4
线程B运行,x = 5
线程A运行,x = 2
线程A运行,x = 3
线程A运行,x = 4
线程A运行,x = 5
线程A运行,x = 6
线程A运行,x = 7
线程A运行,x = 8
线程A运行,x = 9
线程B运行,x = 6
线程B运行,x = 7
线程B运行,x = 8
线程B运行,x = 9
线程C运行,x = 3
线程C运行,x = 4
线程C运行,x = 5
线程C运行,x = 6
线程C运行,x = 7
线程C运行,x = 8
线程C运行,x = 9

此时,不但实现了多线程的启动,而且没有了单继承局限。

3、实现多线程的第三种方法:.使用Callable接口实现多线程

使用Runnable接口实现的多线程可以避免单继承局限,但是有一个问题,Runnable接口里面的run()方法不能返回操作结果。为了解决这个问题,提供了一个新的接口:Callable接口(java.util.concurrent.Callable)。

public interface Callable<V>{
 public V call() throws Exception;
}

执行完Callable接口中的call()方法会返回一个结果,这个返回结果的类型由Callable接口上的泛型决定。

实现Callable接口来实现多线程的具体操作是:
创建Callable接口的实现类,并实现clall()方法;然后使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。

定义一个线程主体类:

import java.util.concurrent.Callable;

class MyThread implements Callable<String>{

 private int ticket = 10;
 @Override
 public String call() throws Exception {
 for(int i = 0 ; i < 20 ; i++){
  if(this.ticket > 0){
  System.out.println("卖票,剩余票数为"+ this.ticket --);
  }
 }
 return "票已卖光";
 }

}

Thread类没有直接支持Callable接口。而在JDK1.5之后,提供了一个类:

java.util.concurrent.FutureTask<V>

这个类主要负责Callable接口对象操作。其定义结构如下:

public class FutureTask<V>
extends Object
implements RunnableFurture<V>

而RunnableFurture这个接口又有如下定义:

public interface RunnableFurture<V>
extends Runnable,Future<V>

在FutureTask 类里面定义有如下构造方法:

public FutureTask(Callable<V> callable)

现在,终于可以通过FutureTask类来接收Callable接口对象了,接收的目的是为了取得call()方法的返回结果。

从上面分析我们可以发现:
FutureTask类可以接收Callable接口对象,而FutureTask类实现了RunnableFurture接口,RunnableFurture接口又继承了Runnable接口。

于是,我们可以这样来启动多线程:

public class TestDemo {
 public static void main(String[] args) throws Exception {
 MyThread mt1 = new MyThread();
 MyThread mt2 = new MyThread();

 FutureTask<String> task1 = new FutureTask<String>(mt1);//取得call()方法返回结果
 FutureTask<String> task2 = new FutureTask<String>(mt2);//取得call()方法返回结果

 //FutureTask是Runnable接口的子类,可以使用Thread类的构造来接收task对象
 new Thread(task1).start();
 new Thread(task2).start();

 //多线程执行完毕后,可以使用FutureTask的父接口Future中的get()方法取得执行结果
 System.out.println("线程1的返回结果:"+task1.get());
 System.out.println("线程2的返回结果:"+task2.get());
 }
}

运行结果:

卖票,剩余票数为10
卖票,剩余票数为10
卖票,剩余票数为9
卖票,剩余票数为8
卖票,剩余票数为7
卖票,剩余票数为9
卖票,剩余票数为6
卖票,剩余票数为8
卖票,剩余票数为5
卖票,剩余票数为7
卖票,剩余票数为4
卖票,剩余票数为6
卖票,剩余票数为3
卖票,剩余票数为5
卖票,剩余票数为2
卖票,剩余票数为4
卖票,剩余票数为1
卖票,剩余票数为3
卖票,剩余票数为2
卖票,剩余票数为1
线程1的返回结果:票已卖光
线程2的返回结果:票已卖光

小结:

上述讲解了三种实现多线程的方式,对于线程的启动而言,都是调用线程对象的start()方法,需要特别注意的是:不能对同一线程对象两次调用start()方法。

(0)

相关推荐

  • 详解Java多线程编程中互斥锁ReentrantLock类的用法

    0.关于互斥锁 所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别: synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是

  • java多线程编程之为什么要进行数据同步

    Java中的变量分为两类:局部变量和类变量.局部变量是指在方法内定义的变量,如在run方法中定义的变量.对于这些变量来说,并不存在线程之间共享的问题.因此,它们不需要进行数据同步.类变量是在类中定义的变量,作用域是整个类.这类变量可以被多个线程共享.因此,我们需要对这类变量进行数据同步.数据同步就是指在同一时间,只能由一个线程来访问被同步的类变量,当前线程访问完这些变量后,其他线程才能继续访问.这里说的访问是指有写操作的访问,如果所有访问类变量的线程都是读操作,一般是不需要数据同步的.那么如果不

  • java多线程编程之使用Synchronized块同步变量

    下面的代码演示了如何同步特定的类方法: 复制代码 代码如下: package mythread; public class SyncThread extends Thread{ private static String sync = ""; private String methodType = ""; private static void method(String s) {  synchronized (sync)  {sync = s;System.out

  • 详解Java多线程编程中CountDownLatch阻塞线程的方法

    直译过来就是倒计数(CountDown)门闩(Latch).倒计数不用说,门闩的意思顾名思义就是阻止前进.在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程. CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. CountDownLatch 的作用和 Thread.join() 方法类似,可用于一组线程和另外一组线程的协作.例如,主线程在做一项工作之前需要一系列的准备工作,只有这些准备工

  • java多线程编程制作电子时钟

    模拟一个电子时钟,它可以在任何时候被启动或者停止,并可以独立的运行. 1.定义一个Clock类.它继承Label类,并实现Runnable接口.这个类中有一个Thread类型的clocker域,以及start()和run()方法.在run()方法中,每隔一秒就把系统时间显示为label的文本. class Clock extends Label implements Runnable { //定义Thread类型的clocker域 public Thread clocker=null; publ

  • Java多线程编程之访问共享对象和数据的方法

    多个线程访问共享对象和数据的方式有两种情况: 1.每个线程执行的代码相同,例如,卖票:多个窗口同时卖这100张票,这100张票需要多个线程共享. 2.每个线程执行的代码不同,例如:设计四个线程,其中两个线程每次对j增加1,另外两个线程每次对j减少1. a.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个对象中有共享数据.卖票就可以这样做,每个窗口都在做卖票任务,卖的票都是同一个数据(点击查看具体案例). b.如果每个线程执行的代码不同,就需要使用不同的Runnable对象,有

  • Java多线程编程之读写锁ReadWriteLock用法实例

    读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可.如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁:如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁.总之,读的时候上读锁,写的时候上写锁! 三个线程读数据,三个线程写数据示例: 可以同时读,读的时候不能写,不能同时写,写的时候不能读. 读的时候上读锁,读完解锁:写的时候上写锁,写完解锁. 注意finally解锁. package com.ljq.test.th

  • Java多线程编程中的两种常用并发容器讲解

    ConcurrentHashMap并发容器 ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,不用对整个ConcurrentHashMap加锁. ConcurrentHashMap的内部结构 ConcurrentHashMap为了提高本身的并发能力,在内部采用了一个叫做Segment的结构,一个Segment其实就是一个类Hash Table的结构,Segment内部维护了一个链表数组,我们用下面这一幅图来看下Con

  • java多线程编程技术详解和实例代码

     java多线程编程技术详解和实例代码 1.   Java和他的API都可以使用并发. 可以指定程序包含不同的执行线程,每个线程都具有自己的方法调用堆栈和程序计数器,使得线程在与其他线程并发地执行能够共享程序范围内的资源,比如共享内存,这种能力被称为多线程编程(multithreading),在核心的C和C++语言中并不具备这种能力,尽管他们影响了JAVA的设计. 2.   线程的生命周期 新线程的生命周期从"新生"状态开始.程序启动线程前,线程一直是"新生"状态:

  • java的多线程用法编程总结

    一.进程与线程 1.进程是什么? 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed). 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元. 2.线程是什么? 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线

  • Java 多线程并发编程_动力节点Java学院整理

    一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理. 线程:表示程序的执行流程,是CPU调度执行的基本单位:线程有自己的程序计数器.寄存器.堆栈和帧.同一进程中的线程共用相同的地址空间,同时共享进进程锁拥有的内存和其他资源. 2.Java标准库提供了进程和线程相关的API,进程主要包括表示进程的jav

  • Java多线程并发编程 Volatile关键字

    volatile 关键字是一个神秘的关键字,也许在 J2EE 上的 JAVA 程序员会了解多一点,但在 Android 上的 JAVA 程序员大多不了解这个关键字.只要稍了解不当就好容易导致一些并发上的错误发生,例如好多人把 volatile 理解成变量的锁.(并不是) volatile 的特性: 具备可见性 保证不同线程对被 volatile 修饰的变量的可见性. 有一被 volatile 修饰的变量 i,在一个线程中修改了此变量 i,对于其他线程来说 i 的修改是立即可见的. 如: vola

  • Java多线程并发编程(互斥锁Reentrant Lock)

    Java 中的锁通常分为两种: 通过关键字 synchronized 获取的锁,我们称为同步锁,上一篇有介绍到:Java 多线程并发编程 Synchronized 关键字. java.util.concurrent(JUC)包里的锁,如通过继承接口 Lock 而实现的 ReentrantLock(互斥锁),继承 ReadWriteLock 实现的 ReentrantReadWriteLock(读写锁). 本篇主要介绍 ReentrantLock(互斥锁). ReentrantLock(互斥锁)

  • Java Thread多线程详解及用法解析

    最全面的java多线程用法解析,如果你对Java的多线程机制并没有深入的研究,那么本文可以帮助你更透彻地理解Java多线程的原理以及使用方法. 1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( ); public Thread(Runnab

  • Java多线程用法的实例详解

    Java多线程用法的实例详解 前言: 最全面的java多线程用法解析,如果你对Java的多线程机制并没有深入的研究,那么本文可以帮助你更透彻地理解Java多线程的原理以及使用方法. 1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( ); p

  • Java多线程并发编程和锁原理解析

    这篇文章主要介绍了Java多线程并发编程和锁原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等方案后,问题得到解决. 加锁方案见下文. 二.乐观锁 & 悲观锁 1.乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁

  • Java  Thread多线程详解及用法解析

    最全面的java多线程用法解析,如果你对Java的多线程机制并没有深入的研究,那么本文可以帮助你更透彻地理解Java多线程的原理以及使用方法. 1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( ); public Thread(Runnab

  • Java 多线程并发编程提高数据处理效率的详细过程

    工作场景中遇到这样一个需求:根据主机的 IP 地址联动更新其他模型的相关信息.需求很简单,只涉及一般的数据库联动查询以及更新操作,然而在编码实现过程中发现,由于主机的数量很多,导致循环遍历查询.更新时花费很长的时间,调用一次接口大概需要 30-40 min 时间才能完成操作. 因此,为了有效缩短接口方法的执行时间,便考虑使用多线程并发编程方法,利用多核处理器并行执行的能力,通过异步处理数据的方式,便可以大大缩短执行时间,提高执行效率. 这里使用可重用固定线程数的线程池 FixedThreadPo

  • Java RandomAccessFile的用法详解

    RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和 DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫

随机推荐