一、进程和线程的理解
1.什么是进程
一个独立的应用程序。比如qq、微信、eclipse等都是一个应用程序
进程需要通过windows系统的分配,获取系统当前的CPU、内存、显卡、网卡等
1.独立性qq运行起来和eclipse软件之间是没有关系的2.互斥性如果一个软件启动起来之后,这个端口被占用以后,其他软件也需要这个端口的话,就启动不了,报端口被占用的错误
2.什么是线程
进程是由多个线程组成的,每个进程里面至少有一个线程。
进程包含线程,线程是组成进程的最小基本单位。
特性:1.抢占式运行cpu在执行的时候,按照时间片来执行的,单位的时间片是互相抢占的比如两个软件的线程在互相抢占,等待的时间很短,人感觉不到2.资源共享型一个线程可以共享当前应用程序的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()方法。
package com.qfedu.test1xiancheng;import java.util.Iterator;//创建线程//方式1class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("MyThread.......");}}}//方式2class MyThread2 implements Runnable{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("MyThread2#########");}}}public class Demo1 {public static void main(String[] args) {for (int i = 0; i < 10; i++) {System.out.println("main");}MyThread myThread = new MyThread();myThread.start();Thread thread = new Thread(new MyThread2());thread.start();}}
三、线程下面的几个方法
构造方法
Thread();分配一个新的Thread对象
Thread(Runnable terget);分配一个新的Thread对象
Thread(Runnable terget,String name);分配一个新的Thread对象,并起名字
成员方法
static Thread currentThread();获取当前线程对象
用法:Thread thread = Thread.currentThread();
String getName();获取该线程的名字
void setName(String name);更改线程的名字
int getPriority();返回次线程的优先级
void setPriority(int newPriority);更改此线程的优先级
优先级1-10,数字越高优先级越高,并不是优先级越高先执行,只是提高概率
static void sleep(long millis);暂停线程(毫秒),可以通过睡眠控制线程执行顺序
让那个线程休眠就写在那个线程里,且异常只能写try-catchrun方法没有抛,子类继承且重写也不能抛
package com.qfedu.test1xiancheng;class MyThread5 implements Runnable{@Overridepublic void run() {//因为牵涉到重写 重写要求比较严格//在重写方法中,sleep方法没有抛出异常的情况,只有try-catch这种情况//在这个重写的方法下面必须try-catch//run方法没有抛,子类继承且重写也不能抛try {Thread.sleep(3000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}for (int i = 0; i < 3; i++) {System.out.println("MyThread5......睡3秒");}}}class MyThread6 implements Runnable{@Overridepublic void run() {for (int i = 0; i < 3; i++) {System.out.println(".......MyThread6不睡");}}}public class Demo4 {public static void main(String[] args) throws InterruptedException {Thread thread5 = new Thread(new MyThread5());//休眠3秒thread5.start();Thread thread6 = new Thread(new MyThread6());//无休眠thread6.start();Thread.sleep(2000);//主线程休眠2秒for (int i = 0; i < 3; i++) {System.out.println("main睡2秒");}}}//.......MyThread6不睡//.......MyThread6不睡//.......MyThread6不睡//main睡2秒//main睡2秒//main睡2秒//MyThread5......睡3秒//MyThread5......睡3秒//MyThread5......睡3秒
四、线程同步和锁
为什么要进行线程同步?
java允许多线程并发操作,当多个线程同时操作一个资源的时候,会导致数据不准确,从而产生冲突,加同步锁,避免线程操作前被其他线程调用,从而保证该遍历的准确性和唯一性。
加锁的目的,只让一个线程进来,等执行玩,其他线程在进行抢占。
解决方法synchronized
使用一个关键字synchronized修饰方法,当使用这个关键字的时候,修饰方法的时候,会保护这个方法
public synchronized void run(){}
以上加了锁,只要一个线程抢到以后,就会卖这10张票
同步代码块的方式:同步代码块就是拥有synchronized关键字修饰的语句块,被修饰的语句块会自动加上锁,从而实现同步
synchronized(this){//this代表两个线程使用的是同一个锁//被加锁的代码}
package com.qfedu.test2suo;//未加锁,死循环且票买到-1//synchronized 修饰方法 进行加锁class MyThread implements Runnable {int ticket = 10;// boolean isFlag = true;@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {// 以下代码是被加锁的代码synchronized (this) {if (ticket > 0) {try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + ticket--);}}}}}public class Demo1 {public static void main(String[] args) {MyThread m1 = new MyThread();Thread thread1 = new Thread(m1, "线程1");Thread thread2 = new Thread(m1, "线程2");Thread thread3 = new Thread(m1, "线程3");thread1.start();thread2.start();thread3.start();}}
【重点】继承Thread方法时,同步锁不可以直接用this
package com.qfedu.test2suo;class MyTh1 extends Thread{private static int i = 0;private static Object obj = new Object();@Overridepublic void run() {while(true) {synchronized (obj) {if (i < 100) {System.out.println(Thread.currentThread().getName() + ":" +i++);}else {break;}}}}}public class Test1 {public static void main(String[] args) {MyTh1 myTh1 = new MyTh1();myTh1.setName("线程1");myTh1.start();MyTh1 myTh2 = new MyTh1();myTh2.setName("线程2");myTh2.start();}}
五、守护线程
守护线程是用来去守护非守护线程的
代码在执行的时候,主线程是非守护线程。
非守护线程执行结束,守护线程就会自动消亡。
package com.qfedu.test2suo;//守护线程是用来 守护 非守护线程的class MyTheard implements Runnable{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println("doloading:" + i + "%");}}}public class Demo4 {public static void main(String[] args) {Thread thread = new Thread(new MyTheard());//把thread设置为主线程的守护线程//一旦主线程执行完毕,守护线程自动挂掉//main和JVM垃圾回收器都是非守护线程 都结束时 守护线程才消亡thread.setDaemon(true);//在start前设置thread.start();for (int i = 0; i < 31; i++) {System.out.println("主线程正在执行" + i);}}}
