进程与线程
定义
进程:进程是系统进行资源分配和调度的一个独立单位。
线程:进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
关系
一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
创建线程的两种方式
继承Thread类
步骤:
- 创建一个子类A继承Thread类。
- 在A中重写Thread类中的run()方法,将要执行的操作编写在方法内。
- 创建线程对象,并用start()方法启动。
注:start()方法中也采用了run()方法。但是如果我们直接调用run()方法,将不会开启新的线程。依旧是在原来的线程中。
public class Threadone extends Thread {
@Override
public void run() {
//任务
}
public static void main (String[] args){
Threadone a = new Threadone();
a.start();
}
}
实现Runnable接口
(方法一)步骤:
- 创建一个子类A实现Runnable接口。
- 实现run()方法。
- 创建A的对象以及线程的对象。
- 调用线程的start();
public class Threadone implements Runnable {
@Override
public void run() {
//任务
}
public static void main (String[] args){
Threadone a = new Threadone();
Thread b = new Thread(a);
b.start();
}
}
(方法二)匿名内部类:
public class Threadone {
public static void main (String[] args){
Thread b = new Thread(new Runnable() {
@Override
public void run() {
//任务
}
});
b.start();
}
}
线程的那些方法
sleep()和yield()
- sleep()可以指定时间,但是yield()不可以。
- 都不会释放锁。
- sleep()允许优先级较低的获得运行机会,yield()不能。
wait(),notify(),notifyAll()
简介:
- 都是属于object类的方法。
- wait()方法可以指定时间也可以不指定。表示某个获取锁的线程释放掉当前的锁。然后该线程就会进入等待池中,等待唤醒。
- notify()会随机唤醒一个等待池中的线程,将它移到锁池中。这时候就可能这个线程依然不满足,还需要等待,就会造成死锁现象。
- notifyAll()会唤醒等待池中的所有线程,然后再竞争,其中一个线程可以获得锁。如果获得锁的线程仍不能执行,就把资源让给下一个。
注意:
- 永远在synchronized的函数或对象里使用wait、notify和notifyAll,不然Java虚拟机会生成 IllegalMonitorStateException。
- 永远在while循环里而不是if语句下使用wait。这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。
- 永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。
- notify ()和wait ()的顺序不能错,如果A线程先执行notify()方法,B线程在执行wait()方法,那么B线程是无法被唤醒的。
实现生产者和消费者问题
参考这篇博客
实现交替打印问题
public class Thread1 extends Thread{ Num num; public Thread1(Num num) { this.num = num; } @Override public void run(){ for (int i = 1;i<=10;i++){ synchronized (num){ while(num.i != 0 ){ try { num.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.print("a"); num.i = 1; num.notifyAll(); } } } } public class Thread2 extends Thread{ Num num; public Thread2( Num num) { this.num = num; } @Override public void run(){ for (int i = 1; i <= 10 ; i++) { synchronized (num){ while(num.i != 1 ){ try { num.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.print("b"); num.i = 0; num.notifyAll(); } } } } public static void main(String []agr){ Num num =new Num(); Thread a = new Thread1(num); Thread b = new Thread2(num); a.start(); b.start(); } }
注意:因为我们锁的对象必须是同一个,所以这里使用String,Integer都是不可以哒~所以自己写了Num类~
public class Num {
int i = 0;
}
还可通过ReentrantLock,即获取锁和释放锁。
suspend()和resume()
为一对,分别是将线程挂起和恢复。现在已经不支持使用这两个了,因为suspend是不释放锁的,如果在resume之前,有一个方法需要使用到suspend中的同一个锁,将会造成“冰冻现象”。解决方法:就是设置一个标记位,当需要挂起的时候就wait,需要恢复就notify。
join()
用来同步。(可以用来实现控制线程按顺序执行)。看源码~
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) { //当线程活着的时候就一直等待。
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
线程的中断机制
关于线程的中断,有两个方法:
- public void interrupt();根据源码上给的注释,这个方法分为四种?情况,有一点看不太懂。第一种情况就是如果线程中断的不是自身,则会调用checkAccess()这个方法,并且抛出SecurityException。第二种情况是如果线程正在执行wait,join,sleep,那么就会抛出InterruptedException,并且清除它的中断状态。第三种情况就是IO阻塞的时候,中断状态会被设置,并且抛出ClosedByInterruptException???第四种就是 如果本身没有阻塞,那么只会设置中断状态。
- public boolean isInterrupted();判断线程的中断状态。
public boolean isInterrupted() {
return isInterrupted(false);//默认false,不会清除中断状态
}
/** * Tests if some Thread has been interrupted. The interrupted state * is reset or not based on the value of ClearInterrupted that is * passed. */
private native boolean isInterrupted(boolean ClearInterrupted);
所以,当我们要中断一个线程的时候,仅仅使用 interrupt()是不够的。
public class TestThread {
static class ThreadA extends Thread{
@Override
public void run() {
for (int j = 0; j < 100; j++) {
System.out.print(j); }
}
}
public static void main(String []agr){
ThreadA a = new ThreadA();
a.start();
a.interrupt();
}
}
运行结果
0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Process finished with exit code 0
那么,我们应该怎么中断一个正在运行的线程呢?可以选择配合isInterrupted();
public class TestThread {
static class ThreadA extends Thread{
int i = 0;
@Override
public void run() {
while(!isInterrupted()){
System.out.print(i++);
}
}
}
public static void main(String []agr){
ThreadA a = new ThreadA();
a.start();
try {
Thread.currentThread().sleep(10);//让主线程先睡一下
} catch (InterruptedException e) {
}
a.interrupt();
}
}
运行结果
0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
Process finished with exit code 0
打印了一会儿之后就停止啦~说明我们中断线程成功~
那我们再来看看处于阻塞状态的情况
public class TestThread {
static class ThreadA extends Thread{
@Override
public void run() {
try {
System.out.print("我睡啦");
sleep(2000);
System.out.print("我睡完啦");
} catch (InterruptedException e) {
e.printStackTrace();
System.out.print("我中断啦");
}
}
}
public static void main(String []agr){
ThreadA a = new ThreadA();
a.start();
a.interrupt();
}
}
运行结果
我睡啦我中断啦java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at TestThread$ThreadA.run(TestThread.java:9)
可以看到它可以成功中断我们的线程~
最后要说的话:其实就是我的一篇笔记啦(这么安慰一下自己,免得自己都嫌弃自己)0 0.最后许个愿吧,希望自己学习进度可以快一点!!路漫漫…黄雅倩快跑起来吧(¬︿̫̿¬☆)还有好多好多需要我去学的 而且今天想好思路的一个算法题还没写,明早一定要先写!哎,渣油。回寝室睡觉啦,明天又是元气满满的一天~!晚安