Uninote
Uninote

java多线程编程

线程的生命周期

  • 新建状态: 使用new关键字创建了一个线程之后,该线程就处于新建状态

  • 就绪状态: 调用了start()方法之后,该线程就进入就绪状态。就绪线程处于就绪队列中,等待JVM里线程调度器的调度。

  • 运行状态: 线程获取 CPU 资源,就可以执行 run(),此时处于运行状态。可变为阻塞状态、就绪状态和死亡状态。

  • 阻塞状态: 程因为某种原因放弃CPU使用权,暂时停止运行,知道进入就绪状态

    ① 等待阻塞:wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)

    ② 同步阻塞:线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

    ③ 其他阻塞:sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(sleep是不会释放持有的锁)

  • 死亡状态: 运行状态的线程完成任务或者其他终止条件发生时

线程创建

  • 实现 Runnable 接口

  • 继承 Thread 类本身

  • 通过 Callable 和 Future 创建线程

实现 Runnable 接口

public class RunnableTest implements Runnable {
    @Override
    public void run() {
        try {
            for (int num = 0; num < 10; num++) {
                System.out.println(Thread.currentThread().getName() + ":" + num);
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        RunnableTest runnableTest = new RunnableTest();
        Thread thread1 = new Thread(runnableTest, "thread1");
        Thread thread2 = new Thread(runnableTest, "thread2");
        thread1.start();
        thread2.start();
    }
}

继承 Thread 类

主要方法
方法 描述
public final void setPriority(int priority) 更改线程的优先级(1-10,10优先级最高)
public final void join(long millisec) 等待该线程终止的时间最长为 millis 毫秒
public void interrupt() 中断线程
public static void yield() 暂停当前正在执行的线程对象,并执行其他线程
public static void sleep(long millisec) 线程休眠
public static Thread currentThread() 返回对当前线程对象的引用
继承 Thread 类实现
public class ThreadTest extends Thread {
    private String name = "";
    private Thread thread;

    public ThreadTest(String name) {
        this.name = name;
    }

    public synchronized void start() {
        if (thread == null) {
            thread = new Thread(this, name);
            thread.start();
        }
    }

    public void run() {
        try {
            for (int num = 0; num < 10; num++) {
                System.out.println(Thread.currentThread().getName() + ":" + num);
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ThreadTest threadTest1 = new ThreadTest("thread1");
        ThreadTest threadTest2 = new ThreadTest("thread2");
        threadTest1.start();
        threadTest2.start();
    }
}

通过 Callable 和 Future 创建线程

  1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,有返回值。

  2. 创建 Callable 实例,使用 FutureTask 类来包装 Callable,FutureTask 封装了 Callable 的 call() 方法的返回值。

  3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。

  4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值

public class CallableTest implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int num = 0;
        for (; num < 100; num++) {
            System.out.println(Thread.currentThread().getName() + " num:" + num);
        }
        return num;
    }

    public static void main(String[] args) {
        CallableTest callableTest = new CallableTest();
        FutureTask<Integer> ft = new FutureTask<Integer>(callableTest);
        new Thread(ft, "Thread").start();
        try {
            System.out.println("返回值:" + ft.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

线程调度

优先级
  • setPriority(int priority) 和 getPriority()
  • static int MAX_PRIORITY 最高10
  • static int MIN_PRIORITY 最低1
  • static int NORM_PRIORITY 默认5
优先级

线程睡眠

  • Thread.sleep(long millis),睡眠指定时间,转到阻塞状态
优先级

线程等待

  • Object类中的wait() 进入线程等待池等待, notify() 方法或 notifyAll() 唤醒
优先级

线程让步

  • Thread.yield() 暂停线程,让给优先级相同或者更高的线程
优先级

线程加入

  • Thread.join() 当前线程中调用另一个线程的join()方法,当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
优先级

线程唤醒 Object类中的notify(),notifyAll() 从等待池中唤醒线程,进入就绪状态

sleep和wait的区别

  1. sleep来自Thread类,wait来自Object类
  2. sleep方法没有释放锁,wait方法释放了锁,进入线程等待池等待,调用notify/notifyAll唤醒等待池中的线程
  3. sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
  4. wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
synchronized(x){
  x.notify()
 //或者wait()
}

线程同步

synchronized
  1. 同步方法
Public synchronized void method(){
    //…..
}
等价于
public void method(){
    synchronized (this){
        //…..
    }
}
  1. 同步块
对象锁
public void method(Object o) {
    synchronized (o) {
        //…..
    }
}
或当没有明确的对象作为锁,想让一段代码同步,可以创建一个特殊的instance变量(它得是一个对象)来充当锁
private byte[] lock = new byte[0];  // 特殊的instance变量
public void method() {
    synchronized (lock) {
        //…
    }
}
  1. synchronized作用于static 函数
class Foo {
    public synchronized static void methodAAA() {
        //….
    }

    public void methodBBB() {
        synchronized (Foo.class) {
        }
    }
}
两个方法效果是一样的,A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class
重入锁
  • 在JavaSE5.0中新增了一个java.util.concurrent包来支持同步
  • ReentrantLock类是可重入、互斥、实现了Lock接口的锁
private int num = 100;
private ReentrantLock lock = new ReentrantLock();

//同步方法
public void add(int a) {
    lock.lock();
    try {
        num += a;
    } finally {
        lock.unlock();
    }

}
局部变量ThreadLocal
  • ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,相互独立,线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
//使用ThreadLocal类管理共享变量num
private static ThreadLocal<Integer> num = new ThreadLocal<Integer>() {
    @Override
    protected Integer initialValue() {
        return 100;
    }
};

public void add(int a) {
    num.set(num.get() + a);
}

其他方法。。。。。。。。。。。。。。。。。。。。。。。。。。

线程死锁

原因
  • 系统资源不足
  • 进程(线程)推进的顺序不恰当
  • 资源分配不当
产生死锁的必要条件
  1. 互斥条件:所谓互斥就是进程在某一时间内独占资源。
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

Spring多线程-TaskExecutor任务调度

java类加载器

点赞(1) 阅读(319) 举报
目录
标题