一、进程和线程的理解

1.什么是进程

一个独立的应用程序。比如qq、微信、eclipse等都是一个应用程序

进程需要通过windows系统的分配,获取系统当前的CPU、内存、显卡、网卡等

  1. 1.独立性
  2. qq运行起来和eclipse软件之间是没有关系的
  3. 2.互斥性
  4. 如果一个软件启动起来之后,这个端口被占用以后,其他软件也需要这个端口的话,就启动不了,报端口被占用的错误

2.什么是线程

进程是由多个线程组成的,每个进程里面至少有一个线程。

进程包含线程,线程是组成进程的最小基本单位。

  1. 特性:
  2. 1.抢占式运行
  3. cpu在执行的时候,按照时间片来执行的,单位的时间片是互相抢占的
  4. 比如两个软件的线程在互相抢占,等待的时间很短,人感觉不到
  5. 2.资源共享型
  6. 一个线程可以共享当前应用程序的CPU、网卡等

java程序:Demo1,就是一个进程,属于应用程序。至少两个线程(main主函数线程和JVM的垃圾回收器)

3.进程和线程的区别

进程是一个完整的应用的程序,就是一个软件

线程是进程里面的最小的基本单位

把进程比作一个生产车间,每个流水线可以当成一个线程

线程没了,进程就没有了

进程申请的资源是系统的资源(CPU、显卡、网卡等)

线程申请的资源是进程的资源

一个进程在执行多线程的时候,CPU会根据每个线程分配的时间片来轮流执行

每个线程占用时间片最多大概20ms。过了这个时间片,切换到另一个线程

抢占式执行,交替执行。人感觉不到

4.并发和并行

并发:同时发生,轮流交替执行

并行:真正意义上的同时执行

5.线程的优缺点

优点

1.提高系统资源的利用率,CPU最大化的利用

2.提高工作效率

3.提升用户体验

缺点

1.加重CPU的负担

2.降低其他线程的执行的概率,应用程序就会卡顿

3.共享资源的问题【重点】

4.死锁的额问题【重点】

二、创建线程的两种方式

1.声明一个Thread的子类,重写run方法,然后实例化该类,然后调用start()方法

2.声明一个类区实现runnable接口,重写run方法,然后实例化Thread,参数为new 实现类,然后调用start()方法。

  1. package com.qfedu.test1xiancheng;
  2. import java.util.Iterator;
  3. //创建线程
  4. //方式1
  5. class MyThread extends Thread{
  6. @Override
  7. public void run() {
  8. for (int i = 0; i < 10; i++) {
  9. System.out.println("MyThread.......");
  10. }
  11. }
  12. }
  13. //方式2
  14. class MyThread2 implements Runnable{
  15. @Override
  16. public void run() {
  17. for (int i = 0; i < 10; i++) {
  18. System.out.println("MyThread2#########");
  19. }
  20. }
  21. }
  22. public class Demo1 {
  23. public static void main(String[] args) {
  24. for (int i = 0; i < 10; i++) {
  25. System.out.println("main");
  26. }
  27. MyThread myThread = new MyThread();
  28. myThread.start();
  29. Thread thread = new Thread(new MyThread2());
  30. thread.start();
  31. }
  32. }

三、线程下面的几个方法

构造方法

Thread();分配一个新的Thread对象

Thread(Runnable terget);分配一个新的Thread对象

Thread(Runnable terget,String name);分配一个新的Thread对象,并起名字

成员方法

static Thread currentThread();获取当前线程对象

  1. 用法:Thread thread = Thread.currentThread();

String getName();获取该线程的名字

void setName(String name);更改线程的名字

int getPriority();返回次线程的优先级

void setPriority(int newPriority);更改此线程的优先级

  1. 优先级1-10,数字越高优先级越高,并不是优先级越高先执行,只是提高概率

static void sleep(long millis);暂停线程(毫秒),可以通过睡眠控制线程执行顺序

  1. 让那个线程休眠就写在那个线程里,且异常只能写try-catch
  2. run方法没有抛,子类继承且重写也不能抛
  1. package com.qfedu.test1xiancheng;
  2. class MyThread5 implements Runnable{
  3. @Override
  4. public void run() {
  5. //因为牵涉到重写 重写要求比较严格
  6. //在重写方法中,sleep方法没有抛出异常的情况,只有try-catch这种情况
  7. //在这个重写的方法下面必须try-catch
  8. //run方法没有抛,子类继承且重写也不能抛
  9. try {
  10. Thread.sleep(3000);
  11. } catch (InterruptedException e) {
  12. // TODO Auto-generated catch block
  13. e.printStackTrace();
  14. }
  15. for (int i = 0; i < 3; i++) {
  16. System.out.println("MyThread5......睡3秒");
  17. }
  18. }
  19. }
  20. class MyThread6 implements Runnable{
  21. @Override
  22. public void run() {
  23. for (int i = 0; i < 3; i++) {
  24. System.out.println(".......MyThread6不睡");
  25. }
  26. }
  27. }
  28. public class Demo4 {
  29. public static void main(String[] args) throws InterruptedException {
  30. Thread thread5 = new Thread(new MyThread5());//休眠3秒
  31. thread5.start();
  32. Thread thread6 = new Thread(new MyThread6());//无休眠
  33. thread6.start();
  34. Thread.sleep(2000);//主线程休眠2秒
  35. for (int i = 0; i < 3; i++) {
  36. System.out.println("main睡2秒");
  37. }
  38. }
  39. }
  40. //.......MyThread6不睡
  41. //.......MyThread6不睡
  42. //.......MyThread6不睡
  43. //main睡2秒
  44. //main睡2秒
  45. //main睡2秒
  46. //MyThread5......睡3秒
  47. //MyThread5......睡3秒
  48. //MyThread5......睡3秒

四、线程同步和锁

为什么要进行线程同步?

java允许多线程并发操作,当多个线程同时操作一个资源的时候,会导致数据不准确,从而产生冲突,加同步锁,避免线程操作前被其他线程调用,从而保证该遍历的准确性和唯一性。

加锁的目的,只让一个线程进来,等执行玩,其他线程在进行抢占。

解决方法synchronized

使用一个关键字synchronized修饰方法,当使用这个关键字的时候,修饰方法的时候,会保护这个方法

  1. public synchronized void run(){
  2. }

以上加了锁,只要一个线程抢到以后,就会卖这10张票

同步代码块的方式:同步代码块就是拥有synchronized关键字修饰的语句块,被修饰的语句块会自动加上锁,从而实现同步

  1. synchronized(this){
  2. //this代表两个线程使用的是同一个锁
  3. //被加锁的代码
  4. }
  1. package com.qfedu.test2suo;
  2. //未加锁,死循环且票买到-1
  3. //synchronized 修饰方法 进行加锁
  4. class MyThread implements Runnable {
  5. int ticket = 10;
  6. // boolean isFlag = true;
  7. @Override
  8. public void run() {
  9. // TODO Auto-generated method stub
  10. while (true) {
  11. // 以下代码是被加锁的代码
  12. synchronized (this) {
  13. if (ticket > 0) {
  14. try {
  15. Thread.sleep(10);
  16. } catch (InterruptedException e) {
  17. // TODO Auto-generated catch block
  18. e.printStackTrace();
  19. }
  20. System.out.println(Thread.currentThread().getName() + ":" + ticket--);
  21. }
  22. }
  23. }
  24. }
  25. }
  26. public class Demo1 {
  27. public static void main(String[] args) {
  28. MyThread m1 = new MyThread();
  29. Thread thread1 = new Thread(m1, "线程1");
  30. Thread thread2 = new Thread(m1, "线程2");
  31. Thread thread3 = new Thread(m1, "线程3");
  32. thread1.start();
  33. thread2.start();
  34. thread3.start();
  35. }
  36. }

【重点】继承Thread方法时,同步锁不可以直接用this

  1. package com.qfedu.test2suo;
  2. class MyTh1 extends Thread{
  3. private static int i = 0;
  4. private static Object obj = new Object();
  5. @Override
  6. public void run() {
  7. while(true) {
  8. synchronized (obj) {
  9. if (i < 100) {
  10. System.out.println(Thread.currentThread().getName() + ":" +i++);
  11. }else {
  12. break;
  13. }
  14. }
  15. }
  16. }
  17. }
  18. public class Test1 {
  19. public static void main(String[] args) {
  20. MyTh1 myTh1 = new MyTh1();
  21. myTh1.setName("线程1");
  22. myTh1.start();
  23. MyTh1 myTh2 = new MyTh1();
  24. myTh2.setName("线程2");
  25. myTh2.start();
  26. }
  27. }

五、守护线程

守护线程是用来去守护非守护线程的

代码在执行的时候,主线程是非守护线程。

非守护线程执行结束,守护线程就会自动消亡。

  1. package com.qfedu.test2suo;
  2. //守护线程是用来 守护 非守护线程的
  3. class MyTheard implements Runnable{
  4. @Override
  5. public void run() {
  6. for (int i = 1; i <= 100; i++) {
  7. System.out.println("doloading:" + i + "%");
  8. }
  9. }
  10. }
  11. public class Demo4 {
  12. public static void main(String[] args) {
  13. Thread thread = new Thread(new MyTheard());
  14. //把thread设置为主线程的守护线程
  15. //一旦主线程执行完毕,守护线程自动挂掉
  16. //main和JVM垃圾回收器都是非守护线程 都结束时 守护线程才消亡
  17. thread.setDaemon(true);//在start前设置
  18. thread.start();
  19. for (int i = 0; i < 31; i++) {
  20. System.out.println("主线程正在执行" + i);
  21. }
  22. }
  23. }