Java基础之线程与多线程操作详解

进程与线程

进程:同一个操作系统中执行的一个子程序,包含了三部分:虚拟CPU、代码、数据。
多进程:同一个操作系统中执行的多个并行的子程序,可以提高CPU的使用率。 线程:在同一个进程当中执行的子程序流。
多线程:在同一个进程当中并发执行的多个子程序流,可以提高CPU的使用率。

进程与线程的区别:

  • 进程有独立的进程空间,进程的数据存放在空间(堆空间和栈空间)是独立的。
  • 线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间是可以影响的。

线程编程的两种方法

一.将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。例如

class PrimeThread extends Thread {
         long minPrime;
         PrimeThread(long minPrime) {
             this.minPrime = minPrime;
         }

         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }

然后可以通过下列代码来启动线程:

PrimeThread p = new PrimeThread(143);
     p.start();

二. 声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。例如

 class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(long minPrime) {
             this.minPrime = minPrime;
         }

         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }

然后通过下面代码来创建并启动线程:

PrimeRun p = new PrimeRun(143);
     new Thread(p).start();

Thread类中的常用方法

  • currentThread() 返回对当前正在执行的线程对象的引用(实现接口方式时使用)。
  • sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。休眠时本线程不会去抢夺执行权限,其他的线程之间都会去抢执行权限,不会考虑优先级。
  • yield() 暂停当前正在执行的线程对象,并执行其他线程。只给本类或者优先级大于本类优先级的线程去抢。
  • join() 等待线程终止。放在start()前面则没有用处
  • setDacemon(boolean on) 将该线程标记为守护线程,守护线程需要依赖其他线程,会在虚拟机停止的时候停止。

注意wait(),nitify(),notifyAll()方法都是Object类中方法,不要搞混。

线程的生命周期

  1. 初始状态:此时线程只是出于JVM进程中,知识创建了一个线程对象,并没有真正开始运行。
  2. 可行动状态:调用线程对象的start()方法,此时线程才真正的被创建,进入可运行状态,等待CPU的调度。即”万事俱备,只欠CPU”。
  3. 运行状态:正在运行的线程,此时它拥有CPU的执行权。
  4. 阻塞状态:运行状态的线程,如果正在等待用用户输入或调用了sleep()和join()等方法都会导致线程进入到阻塞状态,注意从阻塞状态出来的线程不一定马上回到运行状态,而是重新回到可运行状态,等待CPU的再次调度。
  5. 等待队列状态:一个线程调用一个对象的wait()方法会自动放弃该对象的锁标记,进入等待队列状态,只有当有另外一线程调用临界资源的notify()或notifyAll()方法(建议多使用notifyAll方法),才会将等待队列中的线程释放,此线程进入锁池状态。
  6. 锁池状态:每个对象都有互斥锁标记,以防止对临界资源的访问造成数据的不一致,和数据的不完整性。一个线程拥有一个对象的锁标记后,另一对象想访问该对象,必须在锁池中等待,由系统决定哪个线程拿到锁标记并运行,注意从锁池状态出来的线程不是马上回到运行状态,而是重新回到可运行状态,等待CPU的再次调度。
  7. 终止状态:一个线程运行结束后成为终止状态,一个进程只有所有的线程退出后才会终止。

多线程的同步

多线程并发的访问同一个对象(临界资源),如果不对线程进行同步控制,破坏了原子操作(不可再分的操作),则会造成临界资源(两个线程同时访问的资源)的数据不一致
每个对象都有一个互斥的锁标记和一个锁池。当线程拥有这个对象的锁标记时才能访问这个资源,没有锁标记便进入锁池,保证在同步代码块中只有一个线程,解决了多线程同步控制的问题。

java中使用synchronize关键字来对对象或方法设置同步锁,关于次关键字的用法请参看博客Java之synchronize

注意:

  • 在同步语句块中不能直接操作对象锁正在使用的对象。
  • 对象与锁一一对应。
  • 同步依赖对象锁,锁对象相同,同步语句串行,锁对象不同,同步语句并行。
  • 能不用同步就不用同步,由数据共享冲突时才使用同步。

线程间通信使用的空间称之为对象的等待队列,该队列也是属于对象的空间的。使用Object类的wait方法,在运行状态中,线程调用对象的wait()方法,此时表明线程将释放自己所有的锁标记和CPU的占用,同时进入这个对象的等待池。等待池的状态也是阻塞状态,只不过线程释放自己的锁标记。只有在对该对象加锁的同步代码块里才能调用该对象的wait()方法,表示线程将会释放掉所有锁标记,进入等待序列,线程将进入等待队列状态。
一个线程进入了一个队对象加锁的同步代码块,并对该对象调用了wait方法,释放自己拥有的所有锁标记,进入该对象的等待队列,另一个线程获得了该对象的锁标记,进入代码块对该对象调用了notify()或notifyAll()方法,就会在等待队列里释放出线程。进入到锁池状态中。

注意:

  • 使用notifyAll代替notify,因为在调用notify方法时,石油系统决定释放哪个线程。
  • 只能对加锁的资源进行wait和notify。
  • 判断是否进行等待wait时,用while代替if进行判断。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值