Java进程与线程的区别

进程与线程的由来

进程:最开始计算机发展时期,所有的指令都是串行执行,如果遇到用户IO指令,则系统等待用户IO完成之后继续执行指令,极大的浪费CPU时间,为缓解该情况了,引入了指令集的概念,把需要执行的指令都写到一个磁盘上,让操作系统运行,这样批处理操作系统就诞生了,紧接着又遇到一个问题,若一个程序中有任务A与任务B,任务A执行需要大量的IO操作,按照当时的批处理操作系统,仍会等待A,浪费CPU资源,故而想在系统中引入多个程序,那程序之间如何区分,就引入了进程的概念,方便任务A等待IO的过程中,任务B可以抢占CPU,等任务A的IO操作完成,A继续执行,进程是分配资源的最小单位
线程:线程是为了进程内部并发,提高程序的执行效率

进程与线程的区别?

  • 进程是系统分配资源的最小单位,线程是cpu调度的最小单位
  • 进程拥有独立的地址空间,一个进程包含多个线程,多个线程共享地址空间
  • 在java中一个进程对应一个JVM对象实例,多个线程运行在jvm中

线程的Start与Run方法的区别

Start方法会单独启动一个线程执行对应的Run方法
直接调用Run()方法,相当于在主线程中调用Run方法

package com.bdcloud.thread;

public class ThreadTest {

    public static void main(String[] args) {

        MyThread thread = new MyThread();
        thread.run();
        System.out.println("------------------------");
        thread.start();
    }

}
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

//执行结果如下
Connected to the target VM, address: '127.0.0.1:6910', transport: 'socket'
main
------------------------
Thread-0
Disconnected from the target VM, address: '127.0.0.1:6910', transport: 'socket'

Process finished with exit code 0

实现多线程的三种方式

  • 继承Thread实现run方法
  • 实现Runable接口,实现run方法
  • 实现Callable接口,借助FutureTask类,该类本质还是继承了Runable接口,间接的实现了Runable接口
//Callable的示例
public class MyCallbale implements Callable<String> {

   public String call() throws Exception {

       String value = "every thing";
       System.out.println("Task is Reading");
       Thread.sleep(5000);
       System.out.println("Task Done!");
       return value;
   }
}

//使用Callable实现多线程
package com.bdcloud.thread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class FeatureTaskDemo {
   public static void main(String[] args) throws ExecutionException, InterruptedException {
       FutureTask<String> futureTask = new FutureTask<String>(new MyCallbale());
       new Thread(futureTask).start();

       if (!futureTask.isDone()){
           System.out.println("futureTask is not down1");
       }
       System.out.println(futureTask.get());
   }
}
//通过线程池获取线程返回值
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ThreadPoolTest {
   public static void main(String[] args) throws ExecutionException, InterruptedException {
       ExecutorService executorService = Executors.newCachedThreadPool();
       Future<String> submit = executorService.submit(new MyCallbale());
       if (!submit.isDone()){
           System.out.println("futureTask is not down1");
       }
       System.out.println(submit.get());
   }
}

线程的状态

  • 新建状态(New):线程被创建,但是未执行start方法
  • 运行(Runable):分为俩种,Running与Ready,Running状态为获取CPU使用权且在执行,ready为等待Cpu时间
  • 无线等待(Waiting):不会被分配CPU执行时间,需要显示唤醒,例如在synchronize中调用Object.wait()方法
  • 超时等待(Time Waiting):在一定时间内由系统自动唤醒,例如在Synchronized中调用Object.wait(1000)方法
  • 阻塞状态(Blocked):等待获取排它锁
  • 结束(Terminated):已终止线程的状态,线程已经结束执行

线程Sleep与Wait的区别

  • Sleep()是Thread中的方法,Wait是Object中的方法
  • Sleep可以在代码任何部分执行,而Wait仅可以在Synchronize修饰的方法或代码块中执行
  • Sleep仅会让出Cpu时间,不会对锁有改变,Wait同时释放锁跟CPU

Wait与Sleep的Demo

package com.bdcloud.thread;

import lombok.Synchronized;

import javax.sound.midi.Soundbank;

/**
 * 测试Sleep与Wait方法
 */
public class SleepWaitDemo {

    //锁对象
    private static Object lock = new Object();

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程A开始执行,等待获取锁lock");
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock) {
                    try {
                        System.out.println("线程A获取到锁lock");
                        lock.wait(100);
                        System.out.println("线程A执行结束");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程B开始执行,等待获取锁lock");
                synchronized (lock){
                    try {
                        System.out.println("线程B开始执行,已经获取锁lock");
                        Thread.sleep(100);
                        System.out.println("线程B执行完成");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

如何获取线程的返回值

第一种,采用主线程等待法

package com.bdcloud.thread;

public class CycleWait implements Runnable {

    private String value;
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        value = "循环等待赋值value";
    }

    public static void main(String[] args) {
        CycleWait cycleWait = new CycleWait();
        new Thread(cycleWait).start();
        //循环等待
        while (cycleWait.value == null){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("value值="+cycleWait.value);
    }
}

第二种,只用Thread的join方法,阻塞主线程等待子线程执行结束,缺点控制力度不够细

package com.bdcloud.thread;

public class CycleWait implements Runnable {

    private String value;
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        value = "循环等待赋值value";
    }

    public static void main(String[] args) throws InterruptedException {
        CycleWait cycleWait = new CycleWait();
        Thread thread = new Thread(cycleWait);
        thread.start();
        //阻塞主线程等待子线程执行结束
        thread.join();
        System.out.println("value值="+cycleWait.value);
    }
}

第三种,通过Callable接口实现,通过FutureTask或者线程池获取

package com.bdcloud.thread;

import java.util.concurrent.Callable;

/***
 * 定义Callable
 */
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("task is ready to work!");
        Thread.sleep(100);
        System.out.println("task is Done!");
        return "Hello MyCallable!";
    }
}

/***
 * Future 接收Callable的返回值
 */
package com.bdcloud.thread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class FutureTaskTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable callable = new MyCallable();
        //使用FutureTask接收Callable返回的结果
        FutureTask<String> task = new FutureTask<String>(callable);
        //初始化线程
        Thread thread = new Thread(task);
        thread.start();
        while (!task.isDone()){
            System.out.println("task is not finished");
        }
        System.out.println(task.get());
    }
}

package com.bdcloud.thread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/***
 * 使用线程池接收Callbale返回值
 */
public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        //通过线程池提交任务创建子线程执行
        Future<String> submit = executorService.submit(new MyCallable());

        if (!submit.isDone()){
            System.out.println("子线程尚未返回Callable的值");
        }
        try {
            System.out.println(submit.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }finally {
            executorService.shutdown();
        }
    }
}

notify与notyfyAll的区别

首先引入锁池与等待池的概念

  • 锁池

    锁池是当前线程处于等待锁的状态,例如执行到synchronized的方法块时,该锁被另一个线程占用,则自动把该线程放入锁池中,等待竞争CPU资源执行

  • 等待池

    等待池是指在Synchronized代码块中调用lock.wait()方法,线程进入无限等待状态,不会竞争CPU资源

notify方法:其会从等待池中随机唤醒一个线程
notifyAll方法:唤醒等待池中的所有线程进入锁池中

yield方法

暗示Cpu当前线程愿意让出Cpu时间,但是调度器不一定会中断此线程,yield方法不会释放锁

package com.bdcloud.thread;

/***
 * yield测试,运行结果线程A执行为yield()方法后并未让出CPU
 */
public class yieldDemo {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                    if (i == 5){
                        //暗示调度器该线程愿意让出Cpu
                        Thread.yield();
                    }
                }
            }
        };

        Thread a = new Thread(runnable,"A");
        Thread b = new Thread(runnable,"B");
        a.start();
        b.start();

    }
}

interrupt方法

之前终止一个线程,调用stop方法,但是该方法调用容易导致资源尚未释放完整就中断线程 ,现在推荐使用
interrupt方法,该方法调用后会设置该线程的中断标志为true,但是具体中断是由线程自主决定。若当前线程处于等待状态,则抛出异常,线程终止,若线程设置中断标志为true的时候,但还会继续执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值