玩转Java高并发编程

进程和线程的区别

  • 进程是资源分配的最小单位,线程是CPU调度的最小单位
  • 进程是一个资源的容器,为进程里的所有线程提供共享资源,是对程序的一种静态描述,线程是计算机最小的调度和运行单位,是对程序的一种动态描述,一静一动,正好组成了完整的程序
    线程和进程的区别是什么?

线程的生命周期

创建线程的方式

一、继承Thread类创建线程类

(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。

(2)创建Thread子类的实例,即创建了线程对象。

(3)调用线程对象的start()方法来启动该线程。

二、通过Runnable接口创建线程类

(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

(3)调用线程对象的start()方法来启动该线程。

这种方法运用了模板策略:

定义一个算法流程的骨架,把一些可变节点延迟到具体的子类中去执行, 把逻辑实例和线程分开,每个线程共享同一个逻辑,是一种有效减少程序中类的数量的开发模式

//若不重写run方法或传递runnable对象,则不会运行逻辑
Thread()
//Allocates a new Thread object. 
Thread(String name)
//Allocates a new Thread object.指定线程名,默认线程名‘Thread-计数’
Thread(Runnable target)
//Allocates a new Thread object.传递Runnable接口对象
Thread(Runnable target, String name)
//Allocates a new Thread object.指定线程名,默认线程名‘Thread-计数’

//线程组是为了更好的统一对线程管理,比如同时关闭组内所有线程
Thread(ThreadGroup group, Runnable target)
//Allocates a new Thread object.指定线程组,默认线程组为父线程的组
Thread(ThreadGroup group, Runnable target, String name)
//Allocates a new Thread object so that it has target as its run object, has the specified name as its name, and belongs to the thread group referred to by group.
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
//Allocates a new Thread object so that it has target as its run object, has the specified name as its name, and belongs to the thread group referred to by group, and has the specified stack size.
//stacksize是指线程占用的栈深(递归溢出的大小),栈深越大,栈内线程可用数越少
//受操作系统影响,有些平台上未必有用
Thread(ThreadGroup group, String name)
//Allocates a new Thread object.

守护线程

void	setDaemon(boolean on)
//Marks this thread as either a daemon thread or a user thread.

在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程),守护线程会伴随创建线程结束而结束。这个特点使用妥当可以用来结束和释放线程,不妥当会出现线程莫名中断或退出

Join方法

主线程进入阻塞状态,让“主线程”等待“子线程”结束之后才能继续运行。
注意 是调用join()方法的当前线程进入阻塞,而不是调用的线程对象进入阻塞

// 主线程
public class Father extends Thread {
    public void run() {
        Son s = new Son();
        s.start();
        s.join();
        ...
    }
}
// 子线程
public class Son extends Thread {
    public void run() {
        ...
    }
}

Interrupt方法

那么不能直接把一个线程搞挂掉, 但有时候又有必要让一个线程死掉, 或者让它结束某种等待的状态 该怎么办呢?一个比较优雅而安全的做法是:使用等待/通知机制或者给那个线程一个中断信号, 让它自己决定该怎么办。

  • 调用thread.interrupt(),会告知被调用线程中断状态为true.
  • 对于非阻塞中的线程, 只是中断状态改变为true
  • 对于阻塞状态中的线程, 比如等待在这些函数上的线程, Thread.sleep(), Object.wait(), Thread.join(), 这个线程收到中断信号后, 会抛出InterruptedException,同时中断状态改变为false,因为抛出异常意味着该线程已被打断。
  • 在使用synchronized关键字获取锁的过程中不响应中断请求,即线程interrupt后仍需要争抢锁才能响应中断请求。如果这对程序是一个问题,可以使用显式锁,即java中Lock接口,它支持以响应中断的方式获取锁。

获取中断状态

  • Thread.currentThread().interrupt();该方法返回为true的时候,会将中断状态重置为false
  • Thread.isInterrupted();该方法不会重置中断状态,且为静态方法

注意事项:Thread.join(),中断信息发送的不是给Thread,而是执行Thread.join()的线程

线程结束

线程结束不推荐stop()方法,并且该方法已明确过时。

如何优雅的结束线程

1. 设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出

class Demo {
	private class ThreadSafe extends Thread {
	    @Override
	    public void run() { 
	        while (exit){
	            //do something
	        }
	    } 
	}
	private void shutDown(){
		exit = false;
	}
}

2. 捕获异常+中断状态标志判断

public class ThreadSafe extends Thread {
    public void run() { 
        while (!isInterrupted()){ //非阻塞过程中通过判断中断标志来退出
            try{
                Thread.sleep(5*1000);//阻塞过程捕获中断异常来退出
            }catch(InterruptedException e){
                e.printStackTrace();
                break;//捕获到异常之后,执行break跳出循环。
            }
        }
    } 
}

2. 守护线程强制中断退出

因为有可能程序在中间阻塞,无法执行首位置的判断语句,因此需要一个强制退出的方案

public class ThreadService {
    private Thread execuateThread;
    private boolean isFinished;
    private Long currentTimeMillis;
    public void excute(Thread thread){
        execuateThread = new Thread(){
            @Override
            public void run() {
                isFinished = false;
                thread.setDaemon(true);
                thread.start();
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    System.out.println("线程超时被打断");
                }
                isFinished = true;
                System.out.println("线程执行完成");;
            }
        };
        execuateThread.start();
    }
    //等待mill毫秒后若线程还在运行则将其中断
    public void stop(long mill){
        currentTimeMillis = System.currentTimeMillis();
        while (!isFinished){
            if(System.currentTimeMillis()-currentTimeMillis>mill){
                execuateThread.interrupt();
                break;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值