进程与线程

进程

进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位,比如我们windows电脑上运行的一个程序就是一个进程。在传统进程中进程是资源分配和调度的一个基本单位,在后来引入线程概念后,进程就变成了资源分配的基本单位但不是调度的基本单位。

为什么要有线程

在说线程前,总结下进程的特点:

  1. 进程是一个可拥有资源的独立单位;
  2. 进程是一个可独立调度和分派的基本单位。

这样来看的话好像是没什么问题,但是在多任务环境中,不可能说让所有任务排队,前面的处理完了才处理后面的任务。如果要让用户感觉到任务都是一起执行的,那么就必须在进程之间频繁切换。问题在于如果要进行进程的切换需要做很多的工作,必须要保存好当前CPU的上下文,好让CPU下次被分配到当前进程时可以继续往前执行,然后还需要设置新的进程的CPU上下文,在这个过程中会花费很多时间。由于这个原因就限制了系统中进程数目不能多。

为了解决这个限制,后来提出将进程的两个属性分开,由操作系统分开处理,即对于作为调度和分派的基本单位,但不同时作为拥有资源的单位;而对于拥有资源的基本单位,又不对其进行频繁的切换。正是在这种思想的指导下,形成了线程的概念。

线程

在多线程操作系统中中,通常是在一个进程中包括多个线程,每个线程都是独立调度和分派的基本单位。资源由进程来拥有,线程不拥有资源。同一个进程之间的线程切换不会导致进程的切换,只有不同进程间的线程切换才会导致进程切换。而且线程的切换则仅需保存和设置少量寄存器内容,不会同进程切换需求创建和销毁进程控制块等,所以非常迅速,所以其十分适合高并发环境。

线程的状态(Java)

    public enum State {
NEW,//新建 线程被创建,但是没有调用start方法 RUNNABLE,//可运行 表示当前线程可以运行,但实际是否运行有cpu决定 BLOCKED,//阻塞 其他线程获得锁,当前线程被阻塞在获得锁处 WAITING,//等待 等待其他条件成熟进入可运行状态 TIMED_WAITING,//计时等待 在一个指定时间内等待,超时后放弃 TERMINATED;//终止 线程执行完毕
}

线程的创建方式

Thread

继承Thread类:

class TestThread extends Thread{
@Override
public void run() {
super.run();
//do working
}
}
Runnable

实现Runnable接口:

static class TestRunnale implements Runnable{

        @Override
public void run() {
//do working
}
} public static void main(String[] args) {
TestRunnale runnale = new TestRunnale();
Thread thread = new Thread(runnale);
thread.start();
}

线程的中断

不安全的中断

Thread的api中提供了一些终止线程的方法,比如stop()suspend(),resume(),但是这些方法目前在JDK中已经被标记位过时,因为这些方法具有死锁倾向,已经被明确表示不支持使用。

中断线程API

interrupt() 中断线程,本质是将线程的中断标志位设为true,其他线程向需要中断的线程打个招呼。是否真正进行中断由线程自己决定。

isInterrupted() 线程检查自己的中断标志位

静态方法Thread.interrupted() 将中断标志位复位为false

中断标志位

自定义一个Boolean类型的中断标志位,提供一个中断方法,线程一直循环检测该标志位,标志位被设置为退出状态是终止线程。

public class FlagCancel {
static class Flag extends Thread{
//中断标志
public static boolean flag = false; @Override
public void run() {
int i = 0;
while(!flag){
System.out.println(i++);
if(i>=3){
try {
Thread.sleep(200);
//interrupt();
if(i == 10)
cancel();//修改中断状态,退出线程
System.out.println("thread:" + isInterrupted());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cancel...");
}
}
} public static void cancel(){
flag = true;
}
} public static void main(String[] args) {
Flag test = new Flag();
test.start();
test.setPriority(10);//这里的设置优先级其实没什么用。cpu不会理你的。。。
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main:" + test.isInterrupted());//这里属于主线程(main)
}
}

正常来说上面的形式没有什么问题,我们写代码的时候,提供一个修改中断为状态的方法,并根据我们自己的业务逻辑来定义什么时候中断,但是如果我们手动设置中断就有问题了,将上面代码中注释的interrupt();打开。interrupt()方法是用来中断线程的,但是在上面的逻辑中即使调用了该方法也不会立即中断,而必须要等待中断为被修改后才能退出。

安全的中断

上面介绍了中断相关的api和使用中断标志位来中断线程,但是中断标记位无法捕获异常情况。但是isInterrupted()方法会一直检查线程的中断状态,所以我们可以用这个方法来实现安全的中断。

public class SafeInterrupt extends Thread {

    private boolean flag = false;

    @Override
public void run() {
int i = 0;
System.out.println(Thread.currentThread().getName() + ":" +Thread.currentThread().isInterrupted());
while (!flag && !Thread.currentThread().isInterrupted()) {
System.out.println(i++);
try {
synchronized (this) {
if (i > 3) {
//Thread.sleep(1000 * 60 * 60 * 24);
wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} /**
* 这里必须将需要中断的线程作为参数传过来
* 用以进行中断
* @param t(Thread)
*/
public void cancel(Thread t) {
System.out.println("ready stop currentThread...");
flag = true;
//将需要中断的线程的中断标志位设置为true
t.interrupt();
System.out.println(t.getName() + ":" + t.isInterrupted());
} public static void main(String[] args) throws InterruptedException {
SafeInterrupt safeInterrupt = new SafeInterrupt();
safeInterrupt.start();
Thread.sleep(100);
safeInterrupt.cancel(safeInterrupt);
}
}
不可中断的情况

好了,到现在我们已经可以安全的处理线程的中断了,但是还没完,因为不是所有的线程都是会响应中断的。比如IO的read()/write() 等就不会响应中断。而如果我们想不让其继续阻塞的话就需要我们手动的关闭底层的套接字。

public class CloseSocket extends Thread {
private Socket socket;
private InputStream in; public CloseSocket(Socket socket, InputStream in) {
this.socket = socket;
this.in = in;
} //重写中断方法 在中断线程时中断套接字
@Override
public void interrupt() {
try {
//关闭底层套接字
socket.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
//中断线程
super.interrupt();
} }
}

还有想死锁之类的不响应中断的情况用代码已经基本解决不了了,只能检查代码修改重启服务器啦。

Java多线程之一的更多相关文章

  1. 40个Java多线程问题总结

    前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...

  2. Java多线程基础知识篇

    这篇是Java多线程基本用法的一个总结. 本篇文章会从一下几个方面来说明Java多线程的基本用法: 如何使用多线程 如何得到多线程的一些信息 如何停止线程 如何暂停线程 线程的一些其他用法 所有的代码 ...

  3. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

  4. Java多线程系列--“JUC锁”04之 公平锁(二)

    概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...

  5. Java多线程--让主线程等待子线程执行完毕

    使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待. java.util.concurrent.CountDownLatch 使用c ...

  6. Java多线程 2 线程的生命周期和状态控制

    一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...

  7. java 多线程 1 线程 进程

    Java多线程(一).多线程的基本概念和使用 2012-09-10 16:06 5108人阅读 评论(0) 收藏 举报  分类: javaSE综合知识点(14)  版权声明:本文为博主原创文章,未经博 ...

  8. 一起阅读《Java多线程编程核心技术》

    目录 第一章 Java多线程技能 (待续...)

  9. 第一章 Java多线程技能

    1.初步了解"进程"."线程"."多线程" 说到多线程,大多都会联系到"进程"和"线程".那么这两者 ...

  10. java从基础知识(十)java多线程(下)

    首先介绍可见性.原子性.有序性.重排序这几个概念 原子性:即一个操作或多个操作要么全部执行并且执行的过程不会被任何因素打断,要么都不执行. 可见性:一个线程对共享变量值的修改,能够及时地被其它线程看到 ...

随机推荐

  1. JSP:getOutputStream() has already been called for this response

    JSP页面,用小脚本显示一张图片 <%@page import="java.io.OutputStream"%> <%@page import="jav ...

  2. [少数派]如何学习Git

    用玩游戏的方式学习 Git 目录 为什么要学习 Git 怎么学习 Git Learn Git Branching 其他学习资源 用游戏的方式来学习,是一种有趣而高效的方式. 从刚接触电脑时的打字练习软 ...

  3. FTP模式简式:PORT/PASV/EPRT/EPSV

    简介 常见FTP有两种模式:PORT(主动模式).PASV(被动模式). 而EPRT/EPSV模式出现的原因是FTP仅仅提供了建立在IPv4上进行数据通信的能力,它基于网络地址是32位这一假设.但是, ...

  4. contaner

    what Container技术是直接将一个应用程序所需的相关程序代码.函式库.环境配置文件都打包起来建立沙盒执行环境 history 早在1982年,Unix系统内建的chroot机制也是一种Con ...

  5. Codeforces 1065 简要题解

    文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 GGG题略难,膜了一波zhouyuyang{\color{red} zhouyuyang}zhouyuyang巨佬的代码. 其余都挺清真的. ...

  6. dremio jdbc使用

    驱动包地址 链接:https://pan.baidu.com/s/1Nivkvze24hRH8pXOQleCgw 提取码:gp9z 使用dremio主要原因 : 1)springboot提供了es组件 ...

  7. s6-9 TCP 定时器

    TCP 定时器管理  重传定时器(retransmission timer,Positive ackn. with retransmit) 最重要的定时器 TCP 定时器管理  持续定时器(per ...

  8. 欣赏<沉默的大多数>——王小波

    君特·格拉斯在<铁皮鼓>里,写了一个不肯长大的人.小奥斯卡发现周围的世界太过荒诞,就暗下决心要永远做小孩子.在冥冥之中,有一种力量成全了他的决心,所以他就成了个侏儒.这个故事太过神奇,但很 ...

  9. C#中数组、ArrayList和List三者的区别 转

    在C#中数组,ArrayList,List都能够存储一组对象,那么这三者到底有什么样的区别呢. 数组 数组在C#中最早出现的.在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也很简单. ...

  10. 剑指C++面试

    传闻公司老总欠下巨款,带着小姨子跑路了~  树倒猢狲散,接下来要好好准备面试,以期找到一份满意的工作. 面试准备分下面几个方面进行,形成面试系列文章,文章内容以问答的方式呈现. 1.C++语言基础 传 ...