Java多线程

进程和线程

返回目录
在学习多线程之前要理解两个概念:进程和线程.

进程

由操作系统管理的最基本的运行单元,每个进程都有独立的内存空间.比如浏览器,编辑器等都是一个进程.

线程

进程里独立运行的子任务.比如浏览器要处理页面显示,数据请求,文件下载等任务,如果没有给每个任务分配一个线程,那么这些任务只能轮循执行,不能同步执行,就会给用户造成延迟的感觉.给每个任务单独分配线程后,所有的任务都能在系统管理下,会给每个任务分配一定的执行时间,给用户的感觉就是所有的任务是同步执行的.当然这种分配每个操作系统所使用的方式是不一样的,有的是每个任务分配的时间一致,有的是优先级越高,获取的运行时间越多.

线程安全

返回目录
  在线程安全的定义中,最核心的概念就是正确性和一致性,当多线程访问某个类时,都能表现出正确的行为,并且与单线程访问时是一致的,那么这便可以称为这个类是线程安全的.
  无状态的对象一定是线程安全的.如果类方法中存在变量,由于类方法中的变量是存放在栈中的,不同的线程不会共享类方法中的变量.也就不会造成线程安全问题.

原子性

返回目录
  原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分。将整个操作视作一个整体是原子性的核心特征.
  比如以下例子.并不是一个原子操作.
  包括了三个步骤:
  1.从内存中读取count值;
  2.将count值加1;
  3.将修改后的count值写入内存中;
以上的三个步骤在多线程运行环境下,都有可能被打断,导致出现数据出错.  

count++;

多线程实现

返回目录
  创建线程有两种方式,一种是继承Thread.另一种是实现Runable接口.
从源码中可以看出.Thread实现了Runnable.Thread可以通过Runnable初始化一个线程.
 不管用何种方式创建线程类,必须覆盖run()方法,run()方法就是线程运行时所执行的指令.


//Runnable接口定义,只有一个run()方法
public interface Runnable {
    public abstract void run();
}

public class Thread implements Runnable {
    //注册一个线程
     public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    //通过Runnable注册一个线程
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
     @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
    //等其他变量和方法
}

继承Thread类

class MyThread extends Thread {

    @Override
    public void run() {
        System.out.println("继承Thread实现多线程");
        System.out.println("线程:" + Thread.currentThread().getName() + "运行." );
    }
}

实现Runable接口

class MyThread1 implements Runnable{

    @Override
    public void run() {
        System.out.println("实现Runnable接口实现多线程");
        System.out.println("线程:" + Thread.currentThread().getName() + "运行." );
    }
}

测试

public static void main(String[] args) {

    System.out.println("主线程:" + Thread.currentThread().getName() + "执行");
    //继承Thread实现多线程
    MyThread thread1 = new MyThread();
    thread1.start();

    //实现Runnable接口实现多线程
    MyThread1 thread2 = new MyThread1();
    Thread thread3 = new Thread(thread2);       
    thread3.start();
}

输出

主线程:main执行
继承Thread实现多线程
线程:Thread-0运行.
实现Runnable接口实现多线程
线程:Thread-1运行.

可以看到,系统给主线程分配的名字是main,其他的为Thread-x;

选用Thread还是Runnable实现

由于Java里面是单继承多接口,因此使用Runnable比较好.这样还可以继承其他类.

线程的运行

  由以上可知,线程的运行使用start()方法而不是直接调用run()方法,前者由系统进行管理,分配运行时间,后者会直接运行.

线程的结束

1.当线程执行完run()方法后,该线程便结束.
2.当线程run()执行过程中,如果出现异常,线程也会结束.

线程的状态

返回目录
这里写图片描述
从上图可知线程有如下六种状态(该状态在java.lang.Thread中的内部枚举类state中进行定义):

  1. NEW-新创建
  2. RUNNABLE-可运行的状态
  3. BLOCKED-阻塞状态
  4. WAITING-等待状态
  5. TIMED_WAITING-带超时时间的等待状态
  6. TERMINATED-结束状态

NEW-新创建:
当new 一个thread后,并且没有调用thread.start();时所处的状态.
RUNNABLE-可运行的状态:
当执行thread.start();便进入可运行的状态,该状态包含两种状态准备和正在运行的状态,由于操作系统分配的时间片不固定,线程会在两个小状态之间来回切换.
BLOCKED-阻塞状态:
当该线程试图获取某个对象锁时,但是这个对象锁被其他线程所持有,那么该线程便会进入阻塞状态,直到获取到锁.
WAITING-等待状态 和 TIMED_WAITING-带超时时间的等待状态
线程进入等待状态.TIMED_WAITING是带了超时时间,如果超时时间到,就退出等待状态.
TERMINATED-结束状态: 
1.当线程执行完run()方法后,该线程便结束.
2.当线程run()执行过程中,如果出现异常,线程也会结束.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值