进程: 操作系统运行程序时分配资源的最小单位,进程和进程之间是相互独立的
线程: cpu调度的最小单位,它必须依赖于进程.线程在运行时会占用该进程的部分资源,线程之间是可以共享该进程所拥有的全部资源.但是线程与线程之间也有自己的独立空间,称之为线程私有空间.
讲到线程,一个进程有多个线程,所以会有多线程并发问题出现.
什么是并发: 并发就好比一条高速收费口(这就相当于一个进程),假如这个入口有8个收费口,就代表着这个进程开了8个线程一直在跑. 这时并发好比在一个小时一共有多少汽车通过了这个收费口.这就是并发量, 这个并发控制不好就会出现排长队现象,也就是影响性能.
在操作多线程中需要考虑以下事项
1:线程和线程之间的安全性
因为一个进程中多线程是资源共享的,也就是都可以访问同一内存地址当中的一个变量.
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的.
若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全.
2:线程之间的死循环过程
在解决1中线程安全性问题,会引入java的锁机制,如果一旦产生死锁,这时就会发生不可想象的事情.
假如有三个线程,主线程main,和二个子线程A B; 还有二个锁lock1, lock2
二个子线程在跑的时候,假如线程A在执行的时候需要获取锁lock1, 在执行代码时又需要获取锁lock2,
线程B它需要获取锁lock2,在执行代码的时候又需要获取锁lock1.
而在多线程中就可能发生这样的事情, 线程A一直在等锁2释放,而线程B一直在等锁lock1释放.这样线程AB就会出现死锁现象,而这时main线程需要lock1或者Lock2的话,这样就一直获取不了,这就主线程就会阻塞.
(3)线程太多了内存不足的情发生
因为每创建一个线程,在运行这个线程的时候都会为它分配一定资源,而且在创建的时候也是很耗性能的,所以在一直创建线程的时候就会导致性能很差,慎致内存不够用的情况发生.在开发中一般操作线程都会用到线程池来处理.
线程的启动
启动线程有的方式
1: Thread thred = new Thread(); thread.start();
2: X implements Runnable; Thread thred = new Thread(new X()); thread.start();
3: MyCallable implements Callable ;使用Callable的时候又会涉及到FutureTask用法如下
FutureTask future = new FutureTask<>(callable);
Thread thread = new Thread(future);
thread.start();
线程如何停止
首先开户一个线程
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
thread.interrupt()使用线程的这个方法
public static class MyThread extends Thread {
@Override
public void run() {
super.run();
String name = Thread.currentThread().getName();
while (!isInterrupted()) {
System.out.println(name + " === is running");
}
}
}
然后执行thread.interrupt()就可以.
如果在while循环里有sleep的话,就得多加一行代码 ,如下
public static class MyThread extends Thread {
@Override
public void run() {
super.run();
String name = Thread.currentThread().getName();
while (!isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(name + " " + e.getMessage());
interrupt();
}
System.out.println(name + " === is running");
}
}
}
因为sleep当发生异常的时候,会重置isInterrupt这个返回值
sleep wait yield的区别
sleep:
1让该线程进入阻塞状态,告诉系统在指定时间内不要调试该线程,它会让出执行权给其它线程., 到时间后自动恢复,
2当线程处于上锁的时候,这个方法不会释放锁,只会释放CPU的调试权. 当时间到后,也不一定会立马执行,什么时候执行这个取决于系统的调试.
3:执行这个方法时必须捕获异常,因为当其它线程调用了这个线程的interrupt()方法时就会抛出InterruptedException这个异常.
wait:
1: 这个方法是Object里的一个方法,执行它时会让该线程进入阻塞状态
2:当这个线程处于上锁状态时,它会释放这个锁以及让出cpu的调度权,
3:和它搭配的方法有notify(),notifyAll().执行这二个方法就会让等待的线程被激活,但也不是一定会立马执行,得等cpu的调试,如果有锁的话还得等获取锁才能继续执行,
4:wait()方法,notify(),notiftAll()是用于协调多线程对共享数据的存取,所以只能在同步方法或者同步块中使用,否则抛出IllegalMonitorStateException。
yield
1:该方法与sleep()类似,都是可以让当前正在运行的线程暂停,
2:区别在于yield()方法不会阻塞该线程,它只是将线程转换成就绪状态,让系统的调度器重新调度一次,并且yield()方法只能让优先级相同或许更高的线程有执行的机会。