JAVA 线程实现/ 创建
1.继承 Thread 类
Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方
法就是通过 Thread 类的 start()实例方法。start()方法是一个 native 方法,它将启动一个新线程,并执行 run()方法。
public class MyThread extends Thread {
public void run() {
System.out.println("MyThread.run()");
}
}
MyThread myThread1 = new MyThread();
myThread1.start();
- 实现 Runnable 接口
如果自己的类已经 extends 另一个类,就无法直接 extends Thread,此时,可以实现一个Runnable 接口
public class MyThread extends OtherClass implements Runnable {
public void run() {
System.out.println("MyThread.run()");
}
}
3.实现 Callable 接口
执行Callable 任务后,可以获取一个 Future 的对象,在该对象上调用 get 就可以获取到 Callable 任务返回的
Object 了
public class CallableThreadTest implements Callable<Integer> {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CallableThreadTest ctt = new CallableThreadTest();
FutureTask<Integer> ft = new FutureTask<>(ctt);
new Thread(ft, "有返回值的线程").start();
System.out.println("子线程的返回值" + ft.get());
}
@Override
public Integer call() {
int i;
for (i = 0; i < 10; i += 2) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
return i;
}
}
- 基于线程池的方式
ExecutorService threadPool = Executors.newFixedThreadPool(10);
while(true) {
threadPool.execute(new Runnable() { // 提交多个线程任务,并执行
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is running ..");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
线程池
一般的线程池主要分为以下 4 个组成部分:
- 线程池管理器:用于创建并管理线程池
- 工作线程:线程池中的线程
- 任务接口:每个任务必须实现的接口,用于工作线程调度其运行
- 任务队列:用于存放待处理的任务,提供一种缓冲机制
拒绝策略:
1.AbortPolic直接抛出异常
2.CallerRunsPolicy在任务被拒绝添加后,会在调用execute方法的的线程来执行被拒绝的任务。除非executor被关闭,否则任务不会被丢弃。
3. DiscardOldestPolicy : 丢弃最老的一个请求,也就是即将被执行的一个任务
4. DiscardPolicy : 该策略默默地丢弃无法处理的任务
Java 里面线程池的顶级接口是 Executor,但是严格意义上讲 Executor 并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是 ExecutorService。
1.newCachedThreadPool
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行
很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造
的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并 从缓存中移除那些已有 60秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资 源。
2.newFixedThreadPool
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
3.newScheduledThreadPool
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行
4.newSingleThreadExecutor
返回一个线程池(这个线程池只有一个线程),这个线程池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去
线程声明周期
sleep 与 与 wait 区别
- sleep()方法是属于 Thread 类中的。而 wait()方法,则是属于Object 类中的。
- sleep()方法导致了程序暂停执行指定的时间,让出 cpu 该其他线程,但是他的监控状态依然 保持者,当指定的时间到了又会自动恢复运行状态。
- 在调用 sleep()方法的过程中,线程不会释放对象锁。
- 而当调用 wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此 对象调用 notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
start 与 与 run
- start()方法来启动线程,真正实现了多线程运行。这时无需等待 run 方法体代码执行完毕, 可以直接继续执行下面的代码。
- 通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运 行。
- 方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了运行状态,开始运 行 run 函数当中的代码。 Run 方法运行结束, 此线程终止。然后 CPU 再调度其它线程
线程让步(yield ) 会使当前线程让出 CPU 执行时间片
线程中断(interrupt) 给这个线程一个通知信号,会影响这个线程内部的一个中断标识位。这个线程本身并不会因此而改变状态(如阻塞,终止等)。
join()等待其他线程终止,当前线程转为阻塞状态,回到另一个线程结束,当前线程再由阻塞状态变为就绪状态
Object 类中的 notify() 方法,唤醒在此对象监视器上等待的单个线程
JAVA 后台线程
守护线程–也称“服务线程”,他是后台线程,它有一个特性,即为用户线程 提供 公共服务,在没有用户线程可服务时会自动离开。通过 setDaemon(true)来设置线程为“守护线程”,Daemon 线程中产生的新线程也是 Daemon 【垃圾回收线程就是一个经典的守护线程】
ThreadLocal
线程存在ThreadLocal就存在( 使用场景为 用来解决 数据库连接、Session 管理等)
-- 连接池
@Transactional
public void save{
//用 threadlocal 为保证 2个方法获取的是同一个数据库连接
function1();//操作数据库
function2();;//操作数据库
}
-- sesson管理
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}
ThreadLocalMap (线程的一个属性),每个线程中都有一个自己的 ThreadLocalMap 类对象
进程调度算法
1.优先调度算法
a) 先来先服务调度算法 FCFS
b)短作业(进程)优先调度算法 SFJ(SPF)
2.高优先权优先调度算法
3.基于时间片的轮转调度算法