1、线程与进程的:
- 进程:
- 运行中的应用程序,没有运行的程序不算进程
- 进程是Cpu分配资源的最小单位。
- 单核的CPU任何时间点上都只能运行一个进程
- 线程
- 轻量级的进程
- 程序中的一个控制流程,也是CPU的基本调度单位
- 进程可以由单个或者多个线程组成,彼此间完成不同的工作,交替执行,称为多线程
- JVM虚拟机是一个进程,默认的包含主线程(main函数),可以通过代码创建多个独立的线程,与main线程并发执行
- 线程的组成:
- 时间片,由Cpu分配的执行时间
- 运行的数据
- 堆空间:存储线程需要使用的对象,多个线程可以共享堆中的对象
- 栈空间:存储线程需要使用局部变量,每个线程都拥有独立的栈、
- 多线程:
- 宏观并行,微观串行
2、自定义线程
需要继承Thread或者实现Runnable
线程的创建
- 继承Thread类
- 实现Runnable接口
- 他们都需要重写run方法。run方法里面就是调用该线程时需要完成的功能
两种方法的区别
- 第一种方法,可以直接进行对线程的操作,即new出来的对象就是一个线程、代码相比较简单一些,但是只适用于单继承。
- 第二种方法, new出的对象还不是线程,需要创建一个线程,然后把这个对象作为参数创建线程。
- 第二种实现接口的方法,能够实现对象资源的共享
class Test extends Thread { public void run(){ System.out.println("线程名:" + Thread.curreantThread().getName()); } public static void main(String[] args){ Test t = new Test(); t.start(); } }
线程的命名:
对于继承Thread类的线程,可以在构造方法中,调用父类的构造方法,传入线程名。
对于实现Runnable接口的类,因为接口中没有构造方法,因此不能使用上面的方法,但是可以在声明线程的时候,加上线程名。
他们都能调用setName()方法改变线程名
public class Test extends Thread{ private String name ; public Test(String name) { super(name); } public void run() { System.out.println(Thread.currentThread().getName()); } public static void main(String[] args) { Test t1 = new Test("线程A"); Test2 test2 = new Test2(); Thread t2 = new Thread(test2 , "线程B") ; // t1.start(); t2.start(); t1.setName("改变"); t1.start(); } } class Test2 implements Runnable{ public void run() { System.out.println(Thread.currentThread().getName()); } }
调用start()方法与直接调用run()方法的区别
- 调用start()方法,代表了启动一个线程
- 直接调用run()方法,代表的只是单独的调用了run()方法;
线程的优先级Priority
- 分为10级1~10,数字越大级别越高,但是优先级知识代表了获得时间片的概率。
- getPriority()获得该线程的优先级
- setPriority()改变线程的优先级
线程的常用方法
- void setName(String name) 更改线程的名字
- void setPriority(int newPriority) 更改线程的优先级
- static void sleep(long millis) 线程进入睡眠状态millis时间
- void join() 插队,谁调用它,谁先执行
- static void yield() 礼让,主动的放弃时间片,回到就绪状态,竞争下一次的时间片,可能会继续抢到时间片。
- void interrupt() 中断,只是添加一个中断标记,不会立刻停止
- boolean isAlive() 判断线程是否死亡,以弃用
线程的状态
- 初始状态:线程对象被创建,只在堆空间中开辟了内存,与常规的对象一样
- 就绪状态:调用start()方法,进入就绪状态,等待os选中,并且分配时间片
- 运行状态:获得时间片之后,进入运行状态,如果时间片到期,则回到就绪状态。
- 终止状态:主线程或者独立的线程结束,进入终止状态,并且释放所有的时间片
- 阻塞状态:就是其他的线程抢到了同步锁的控制权,其他线程进入阻塞状态。
线程的同步
每一个线程,就拥有一个独立的run方法,因此当一个run方法被return终止的时候,不会因此结束别的线程。
关键字synchronized 有两个适用场景
- 对代码块进行加锁
- 对方法进行加锁
synchronized关键字, ),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。
当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
public class RunThread implements Runnable{ int length = 1000 ; public void run() { for(int i = 0 ; i <= 1000 ; i += 100) { if(length == 0 ) { break; } synchronized (this) { for(int j = 0 ; j <= 100 ; j += 10) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "跑了十米"); } length = length - 100 ; System.out.println(Thread.currentThread().getName() + "跑了一百米 ,换下一人"); System.out.println("还剩下:" + (length) +"米"); return ; } } public class Test { public static void main(String[] args) { RunThread r = new RunThread(); Thread t1 = new Thread(r,"1号" ); Thread t2 = new Thread(r,"2号" ); Thread t3 = new Thread(r,"3号" ); Thread t4 = new Thread(r,"4号" ); Thread t5 = new Thread(r,"5号" ); Thread t6 = new Thread(r,"6号" ); Thread t7 = new Thread(r,"7号" ); Thread t8 = new Thread(r,"8号" ); Thread t9 = new Thread(r,"9号" ); Thread t10 = new Thread(r,"10号" ); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); t7.start(); t8.start(); t9.start(); t10.start(); } }
3、生产者,消费者的问题
主要涉及到是两个Object之中的方法:
void wite(); 使线程进入等待的状态,直到线程被唤醒
void notfiy(); 唤醒线程 ,是随机唤醒
public class Com { private String host ;//主机 private String display ;// 显示器 List<Com> list = new ArrayList<Com>(); public String getHost() { return host; } public void setHost(String host) { this.host = host; } public String getDisplay() { return display; } public void setDisplay(String display) { this.display = display; } public Com(String host , String display) { this.host = host ; this.display = display ; } public Com () {} public String toString() { return "这个电脑是:[主机是:" + host + "=== 显示器是:" + display + "]"; } } public class Consumer implements Runnable{ private Com com = null ; public Com getCom() { return com; } public Consumer(Com com) { this.com = com; } public void run() { for(int i = 0 ; i <= 100 ; i++) { synchronized(com) { if(com.list.size() <= 0 ) { com.notify(); try { com.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else { for(int j = 4 ; j >= 0 ; j--) System.out.println(com.list.remove(j)); } } } } } public class Pro implements Runnable{ private Com com = null ; public Com getCom() { return com; } public Pro(Com com) { this.com = com; } public void run() {ynchronized (com) { for(int i = 1 ; i <= 100; i++) { if(com.list.size() >= 5) { com.notify(); try { com.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else { if (i % 2 == 0) { com.list.add(new Com("华硕" + i,"联想" + i + "号")); }else { com.list.add(new Com("泰坦" + i,"泰泰" + i + "号")); } } } } } } public class Supermarket { public static void main(String[] args) { Com com = new Com() ; Pro pro = new Pro(com); Consumer con = new Consumer(com); Thread t1 = new Thread(pro); Thread t2 = new Thread(con); t1.start(); t2.start(); } }