进程与线程
进程(process)是操作系统的任务单元,每一个程序启动后,操作系统都会为其分配
进程编号PID
线程(Thread)是进程中的任务单元,程序启动的时候,首先会创建主线程,可以在主线程中开辟子线程,每一个线程都对应一个虚拟机栈,栈是线程私有的,堆和方法区是线程共享的
串行:
在一台机器上单线程执行
并行:
并发: 在同一台机器上多线程并行执行(存在资源竞争关系)
并行: 在多台的机器上并行执行(不存在资源竞争关系)
Java中实现多线程的方式有4种
1.继承Thread类,重写run方法
public static void main(String[] args) {
System.out.println("主线程开始");
MyThread mt = new MyThread(); //开辟子线程
mt.start(); //start是子类从父类种继承的方法,start在子线程调用了run()方法
mt.run();//直接调用润,是在房前主线程种调用run
System.out.println("主线程结束");
}
//静态内部类
//实现线程方式1:继承Thread类,重写run方法
static class MyThread extends Thread{
@Override
public void run() {
System.out.println("子线程开始");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程结束");
}
}
2.实现Runnable接口,重写run方法
public static void main(String[] args) {
System.out.println("主线程开始");
MyRunnable myRunnable = new MyRunnable(); //创建Runnable对象
Thread thread = new Thread(myRunnable); //用官方的Thread类创建线程对象,并把Runnable对象作为Thread狗崽方法
thread.start(); //调用start()
//thread.run();
System.out.println("主线程结束");
}
//静态内部类
//实现线程方式2:实现Runnable接口,重写run方法
//Dog的父类是Animal,这时候Dog还能继承Thread吗?
//官方的意思是:当一个类已经有父类了,此时不方便继承Thread,可以采用实现Ruannable接口的方式
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("子线程开始");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程结束");
}
}
3.实现callable接口,重写call方法
public static void main(String[] args) {
MyCallable myCallable = new MyCallable(); //创建一个Callable对象
FutureTask<Integer> ft = new FutureTask<>(myCallable); //创建一个FutureTask对象,用Callable对象作为构造方法的参数
Thread thread = new Thread(ft); //船舰一个Thread对象,用FutureTask对象作为构造方法的参数
thread.start();
//用FutureTask对象的get()方法取子线程call方法的返回值
while (true){
try {
if (ft.isDone()){
Integer sum = ft.get(); //子线程返回值的时候,子线程可以正常返回,也可以异常返回
System.out.println("子线程返回值" + sum);
break;
} else {
System.out.println("子线程未结束!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
//静态内部类
//实现线程方式3:实现callable接口,重写call方法
//需要指定泛型,这个泛型是作为子线程返回值的数据类型
//方式1和方式2都无法实现子线程运行结束后返回一个结果,
static class MyCallable implements Callable<Integer>{
@Override
public Integer call() throws Exception {
Integer sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
Thread.sleep(100);
}
return sum;
}
}
4.使用线程池类
继承Thread类只能单继承,实现Runnable可以实现多继承
实现callable接口,和继承Thread类与实现Runnable相比,可以实现返回值
线程的五种生命周期状态
1.新建(new):新创建了一个线程对象。
2.可运行(runnable):线程对象创建后,当调用线程对象的start()方法,该线程处于就绪状态,等待被线程调度选中,获取cpu的使用权。
3.运行(running):可运行状态(runnable)的线程获得了cpu时间片(timeslice),执行程序代码。
注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
4.阻塞(block):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,
直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。
阻塞的情况分两种:
1.阻塞时候释放锁
2.阻塞时候不释放锁
5.死亡(dead):线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
双向链表的简单实现
public class MyLinkedList<E> {
public static class Node<E>{
E item;
Node<E> next;
Node<E> prev;
public Node( Node<E> next, E item, Node<E> prev) {
this.item = item;
this.next = next;
this.prev = prev;
}
public Node() {
}
}
private Node<E> first;
private Node<E> last;
private int size = 0;
public MyLinkedList() {
}
public void addFirst(E e){
Node <E> f = first;
Node <E> newNode = new Node(null,e,f);
first = newNode;
if (f == null){
last = newNode;
}else{
f.prev = newNode;
}
size++;
}
public void addLast(E e){
linkLast(e);
}
private void linkLast(E e){
Node <E> l = last;
Node <E> newNode = new Node(l,e,null);
last = newNode;
if (l == null){
last = newNode;
}else{
l.next = newNode;
}
size++;
}
public void add(E e){
linkLast(e);
}
public void add(int index,E element){
if(index<0||index>size){
throw new RuntimeException("下标越界");
}
if (index == size){
linkLast(element);
} else {
Node<E> x = node(index);
Node<E> prev = x.prev;
Node<E> newNode = new Node(prev,element,x);
x.prev = newNode;
if (prev == null){
first = newNode;
}else{
prev.next = newNode;
}
size++;
}
}
public E removeFirst(){
if(size==0){
throw new RuntimeException("下标越界或者链表为空");
}
Node<E> e = first;
E element = e.item;
Node<E> next = e.next;
e.item = null;
e.next = null;
if (next == null){
last = null;
}else{
next.prev = null;
}
size--;
return element;
}
public E removeLast(){
if(size==0){
throw new RuntimeException("下标越界或者链表为空");
}
Node<E> e = last;
E element = e.item;
Node<E> prev = e.prev;
e.item = null;
e.prev = null;
if (prev == null){
first = null;
} else {
prev.next = null;
}
size--;
return element;
}
public boolean remove(Object o){
if (o == null){
for(Node<E> x = first;x != null;x = x.next){
if (x.item == null){
unlink(x);
return true;
}
}
} else {
for (Node<E> x= first; x != null; x = x.next){
if (o.equals(x.item)){
unlink(x);
return true;
}
}
}
return false;
}
public E unlink(Node<E> e){
E element = e.item;
Node<E> prev = e.prev;
Node<E> next = e.next;
if (prev == null){
first = next;
} else {
prev.next = next;
e.prev = null;
}
if (next == null){
last = null;
} else {
next.prev = prev;
e.next = null;
}
e.item = null;
size--;
return element;
}
public E get(int index){
if(index<0||index>=size || size==0){
throw new RuntimeException("下标越界或者链表为空");
}
if (size == 0){
System.out.println("下标越界");
return null;
}
return node(index).item;
}
public Node<E> node(int index){
if(index<0||index>=size || size==0){
throw new RuntimeException("下标越界或者链表为空");
}
if (index < (size >> 1)){
Node<E> x = first;
for (int i = 0; i < index; i++) {
x = x.next;
}
return x;
}else {
Node<E> x = last;
for (int i = size - 1; i > index; i--) {
x = x.prev;
}
return x;
}
}
public E set(int index,E element){
if(index<0||index>=size || size==0){
throw new RuntimeException("下标越界或者链表为空");
}
Node<E> x = node(index);
E older = x.item;
x.item = element;
return older;
}
public int size(){
return size;
}
}