线程学习随笔

线程

进程与线程

进程(Process)

说起进程,需要了解程序(Program)。程序是计算机指令和数据的有序集合,而进程就是程序的一次执行过程,是系统资源分配的基本单位。

线程(Thread)

线程是操作系统运算调度的最小单位。一个进程可以包含若干线程。

Java程序运行时 ,至少有一个主线程,主线程是程序的入口,用于执行整个程序,同时运行还有守护进程(daemon),如gc进程(Garbage Collection,垃圾回收),守护进程是一类后台运行的进程。

线程的运行由调度器调度,不受人为干预,并非启动就立即执行。

只有一个cpu的情况下,同一时间cpu只能执行一个线程,因为相互之间切换很快,才会产生同时执行的错觉。

 

实现方式

继承Thread,重写run方法,调用start方法执行线程

Java单继承的特性使之存在局限性

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

        public void run() {
            . . .
        }
  public static void main(String[] args) {
           PrimeThread p = new PrimeThread(143);
  p.start();
      }        
    }

实现Runnable接口,重写run方法,作为参数传入新建的Thread对象,调用start方法

推荐使用,一个对象可被多个线程使用

多线程操作同一资源,会造成资源的过度使用,应添加并发控制。

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

        public void run() {
            . . .
        }
        public static void main(String[] args) {
           PrimeRun p = new PrimeRun(143);
    new Thread(p).start();
      }
    }

属性

static int MAX_PRIORITY 最大优先级 10
The maximum priority that a thread can have.
static int MIN_PRIORITY 最小优先级 1
The minimum priority that a thread can have.
static int NORM_PRIORITY 默认优先级 5
The default priority that is assigned to a thread.

可以通过getPriority()返回线程优先级,通过setPriority(int newPriority)修改优先级,优先级越高,线程会先执行,但仍由调度器调度。

构造器

public Thread()
新建一个Thread对象,同构造器Thread (null, null, gname),gname初始化为"Thread-"+n

public Thread(Runnable target)
新建一个Thread对象,同构造器Thread (null, null, gname),gname初始化为"Thread-"+n
参数:
target - thread调用start时执行的是target对象的run方法

public Thread(String name)
新建一个Thread对象,同构造器Thread (null, null, name).
参数:
name - 线程名称

public Thread(Runnable target,String name)
新建一个Thread对象,同构造器Thread (null, null, name).
参数:
target - thread调用start时执行的是target对象的run方法
name - 线程名称

方法

public static Thread currentThread()  返回当前执行的线程对象

public long getId() 返回线程对象的标识,线程ID实在新建对象初始化的长整型数字,线程运行期间保持唯一并且不可变,线程结束后可重复使用。

public final String getName() 返回线程名称

public Thread.State getState() 返回线程状态

public final boolean isAlive() 检查线程是否依然存活

public final boolean isDaemon() 检查线程是否未守护线程

public final void join() 执行新的线程,只有当前线程死亡后才执行其他线程

public static void sleep(long millis)  当前线程进行进入指定时间内的休眠状态,线程不会释放监视器的所有权

public void start() 唤醒线程,java虚拟机会调用线程的run方法

public static void yield()  线程礼让,线程示意调度器,让出程序的使用权,调度器可以不予理会(重新进入就绪状态,等待被调度)

public final void wait() 父类Object的方法,线程会放弃监视器的所有权,等待着,直到另一个线程通过调用notify方法或notifyAll方法通知在该对象的监视器上等待的线程唤醒。

public final void wait(long timeout) 父类Object的方法,线程会放弃监视器的所有权,等待着,直到另一个线程通过调用notify方法或notifyAll方法通知在该对象的监视器上等待的线程唤醒,或者指定的时间流逝

public final void notify() 唤醒正在该对象的监视器上等待的单个线程。如果有线程正在等待此对象,则选择其中一个线程被唤醒。这种选择是任意的。通过调用wait方法在对象的监视器等待的线程。

在当前线程放弃对该对象的锁定之前,唤醒的线程将无法继续。被唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正积极地在该对象上进行同步;例如,被唤醒的线程在成为下一个锁定此对象的线程时没有可靠的特权或劣势。

对象监视器只能被一个对象占用

public final void notifyAll() 唤醒正在该对象的监视器上等待的所有线程。

在当前线程放弃此对象的锁之前,唤醒的线程将无法继续。被唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正积极地在该对象上进行同步;例如,被唤醒的线程在成为下一个锁定此对象的线程时没有可靠的特权或劣势。

线程状态

NEW 新增状态
A thread that has not yet started is in this state.
Thread类被初始化,还未调用start方法
RUNNABLE 可运行状态
A thread executing in the Java virtual machine is in this state.
调用start方法,等待调度器调度
BLOCKED 阻塞状态
A thread that is blocked waiting for a monitor lock is in this state.
线程被阻塞等待监视器锁
WAITING 等待状态
A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
无限期等待另一个执行特定操作的进程,
wait() 当前线程进入等待状态,直到另一个线程通过notify(),notifyAll()唤醒它
wait(long timeout) 当前线程进入等待状态,直到另一个线程通过notify(),notifyAll()唤醒它,或者指定的时间流逝
notify() 唤醒某个等待状态的线程
notifyAll() 唤醒所有等待状态的线程
三个方法属于父类Object的方法
TIMED_WAITING 定时等待
A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
等待另一个指明了明确的等待时间后执行特定操作的进程
sleep(long millis) 当前线程进行进入指定时间内的休眠状态
TERMINATED 死亡状态
A thread that has exited is in this state.
线程结束

线程同步

synchronize [sɪŋkrənaɪz]

锁是一种工具,用于控制多个线程对共享资源的访问。通常,锁提供对共享资源的独占访问:一次只有一个线程可以获取锁,而对共享资源的所有访问都需要先获取锁。

实现方式

synchronized机制:包括synchronized方法和synchronized块

synchronized方法:是将synchronized关键字作为修饰符加到方法上,默认锁的是this,当前类。

    public sunchronized void method(){}

synchronized块:synchronized 作用于共享的对象。方法内并不是所有的对象的锁都需要被获取。锁的资源越多越浪费。

    synchornized(obj){}

synchronized是隐式锁,出了作用域自动释放。还有一种显式锁java.util.concurrent.locks.lock,其中比较常用的是ReentrantLock(可重入锁),可以实现syncrhoized同样的效果并且有扩展功能。

锁是一种工具,用于控制多个线程对共享资源的访问。通常,锁提供对共享资源的独占访问:一次只有一个线程可以获取锁,而对共享资源的所有访问都需要先获取锁。但是,有些锁可能允许并发访问共享资源,例如读写锁的读锁。

synchronized方法和synchronized块的使用提供了对与每个对象相关联的隐式监视器锁的访问,但是强制所有锁的获取和释放都以块结构的方式进行:当获取多个锁时,它们必须以相反的顺序释放,并且所有锁都必须在它们被获取时所在的同一个词法作用域中释放

 Lock l = new ReentrantLock();
l.lock();
try {
  // access the resource protected by this lock
} finally {
  l.unlock();
}

 

死锁

死锁是指多个线程占用多个资源,并且互相等待其他线程占有的资源才能运行,其他线程就会停止执行,造成死锁。如线程1持有对象A的锁,等待使用对象B的锁,而线程2持有对象B的锁,等待使用A的锁。

synchronized(A){
...
synchronized(B)
}

产生死锁的四个必要条件:

互斥条件:一个资源每次只能被一个进程使用

请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

四个条件同时成立才会死锁。确保至少一个条件不成立即可预防死锁。

线程通信

多个线程相互依赖,一个线程执行到某个条件时通知另一个线程执行。

等待/通知机制

java 提供了wait(),notify(),notifyAll()解决线程之间的通信问题

wait() 当前线程进入等待状态,直到另一个线程通过notify(),notifyAll()唤醒它,与sleep()不同,该方法会释 放锁

wait(long timeout) 当前线程进入等待状态,直到另一个线程通过notify(),notifyAll()唤醒它,或者指定的时间流逝

notify() 唤醒某个等待状态的线程

notifyAll() 唤醒所有等待状态的线程,优先级别高的有限调度

以上方法只能在同步方法或同步代码块里使用

    synchronized (obj) {
        while (<condition does not hold>)
            obj.wait();
        ... // Perform action appropriate to condition
    }
    synchronized (obj) {
        while (<condition does not hold>)
            obj.notify();
        ... // Perform action appropriate to condition
    }

线程池

线程创建和释放,占用大量资源。高并发情况下,影响性能。

提前创建多个线程放入线程池中,实现重复利用,提高响应速度,降低资源消耗,便于管理。

 

class NetworkService implements Runnable {
  private final ServerSocket serverSocket;
  private final ExecutorService pool;

  public NetworkService(int port, int poolSize)
      throws IOException {
    serverSocket = new ServerSocket(port);
    pool = Executors.newFixedThreadPool(poolSize);
  }

  public void run() { // run the service
    try {
      for (;;) {
        pool.execute(new Handler(serverSocket.accept()));
      }
    } catch (IOException ex) {
      pool.shutdown();
    }
  }
}
class Handler implements Runnable {
  private final Socket socket;
  Handler(Socket socket) { this.socket = socket; }
  public void run() {
    // read and service request on socket
  }
}
posted @ 2020-07-19 19:09  ToBeFan  阅读(82)  评论(0)    收藏  举报