-
理解程序、进程、线程的概念
- 程序可以理解为静态的代码
- 进程可以理解为执行中的程序
- 线程是进程的进一步细分,理解为程序的一条执行路劲
-
如何创建Java程序的线程
- 通过继承的方式创建多进程
//1. 创建一个继承自Thread的子类 class SubThread extends Thread{ //2.重写run方法,方法内实现此子线程要完成的工作 public void run(){ for (int i = 0; i <= 100 ; i++) { System.out.println(Thread.currentThread().getName() +":" + Thread.currentThread().getPriority() +":"+i); } } } public class TestThread { public static void main(String[] args) { //3.创建一个子类的对象 SubThread st1 = new SubThread(); //4.调用线程的start方法,启动此线程;JVM调用相应的run方法 //一个线程只能调用一次start方法 st1.start(); //不能通过Thread实现类对象的run方法去启动一个线程,必须start } }
- 通过实现Runnable接口的方式来实现多线程
class PrintNum implements Runnable{ //2. 实现Runnable接口中的抽象方法 public void run(){ //子线程执行的代码 for (int i = 0; i <= 100 ; i++) { if(i % 2 == 0){ System.out.println(Thread.currentThread().getName() + " : " + i); } } } }
- Thread类本身实际上也是实现了Runnable接口的一个实现类。一般来说,
采用实现的方式更好,因为这样可以避开单继承的局限性。
如果多个线程有共享数据的话,更适合使用实现Runnable接口的方式,同时,
共享数据所在的类,可以作为Runnable接口的实现类。
-
常用Thread类方法
start() run() currentThread() getName() setName(String name) yield() sleep() isAlive() notify() notifyALl() getPriority() setPriority(int i)
-
使用多线程的优点
1.提高应用程序的响应,对图形化界面更有意义
2.提高计算机系统CPU的利用率
3.改善程序结构,将既长又复杂的进程分为多个线程,独立运行,利于理解和修改 -
线程分类:
1.守护线程:如Java垃圾回收,若JVM中都是守护线程,当前JVM将退出2.用户线程:在start()之前,调用Thread.setDaemon(),可将用户线程转为守护线程
-
线程的生命周期
- 新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
- 就绪:处于新建状态的线程被start()之后,将进入线程队列等待CPU时间片,此时已具备运行条件
- 运行:就绪线程被调度并获得处理器资源时,编进入运行状态,run()方法定义了线程的操作和功能
- 阻塞:被人为挂起或进行IO时,让出CPU并临时中止自己的执行,进入阻塞状态
- 死亡:线程完成了它的全部工作或线程被提前强制性地中止
-
线程的同步机制
- 如果我们创建的多个线程之间,存在着共享数据,就有可能出现线程安全问题。
当其中一个线程操作共享数据,但操作尚未完成的时候,另外的线程就参与进来,
这就会导致线程安全问题。 - 解决线程安全问题的方法在于,只有当前线程完全操作完共享数据之后,
其他线程才可以操作共享数据。 - 方式一:同步代码块
synchronized(同步监视器){ //操作共享数据的代码 //同步监视器,也叫锁,任何一个类的对象都可以来充当锁 //要想保证线程的安全,必须要求所有的线程公用同一把锁。 //使用实现Run able接口的方式创建接口的话,同步代码块中的锁 //可以考虑使用this对象 //如果使用继承的方法实现多线程,一般不要使用this对象作为锁 //共享数据:多个线程需要共同操作的变量,明确哪部分是操作共享数据的代码 }
- 方式二:同步方法,将操作共享数据的方法声明为synchronized
public synchronized void show(){ //对于非静态的方法而言,使用同步的话,默认锁为this, //如果使用继承的方式使用多线程的话,就要慎用同步方法(默认this锁) //对于静态的方法如果使用同步,默认的锁为当前类本身 }
- 方式一:同步代码块
- 引起锁释放的操作:
- 当前线程的同步方法、同步代码块执行结束
- 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行
- 当前线程在同步代码块、同步方法中出现了未处理的Error、Exception,导致异常结束
- 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁
。需要注意的是,sleep方法并不会导致锁释放,yield方法也不会释放锁。
- 死锁:不同线程分别占用对方所需要的同步资源不放弃,都在等待对方放弃自己所需的同步资源,
就形成了线程的死锁。
- 如果我们创建的多个线程之间,存在着共享数据,就有可能出现线程安全问题。
-
线程通信
- wait():当在同步中执行到此方法,则线程必须等待,直至其他线程执行notify()方法将其唤醒。
唤醒后,继续wait方法后的代码。 - notify() notifyAll():在同步中执行到此方法,则唤醒其他被wait的一个或者所有的线程。
- 上述三个方法必须使用在同步代码块或者同步方法中
- 两个线程交替打印1-100的数字
class PrintNumber implements Runnable { int num = 1; public void run() { while (true) { synchronized (this) { notify(); if (num <= 100) { try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " : " + num); num++; } else break; try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } public class TestCommunication { public static void main(String[] args) { PrintNumber p = new PrintNumber(); Thread t1 = new Thread(p); Thread t2 = new Thread(p); t1.setName("A"); t2.setName("B"); t1.start(); t2.start(); } }
- 生产者消费者问题
class Clerk { int product; //生产产品 public synchronized void addProduct() { if(product >= 20){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else { product++; System.out.println(Thread.currentThread().getName() + ":生产了第" + product + "个产品"); notifyAll(); } } //消费产品 public synchronized void consumeProduct(){ if(product <= 0){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else { System.out.println(Thread.currentThread().getName() + ":消费了第" + product + "个产品"); product--; notifyAll(); } } } class Producer implements Runnable { Clerk clerk; public Producer(Clerk clerk) { this.clerk = clerk; } public void run() { System.out.println("生产者开始生产"); while (true) { clerk.addProduct(); } } } class Consumer implements Runnable { Clerk clerk; public Consumer(Clerk clerk) { this.clerk = clerk; } public void run() { System.out.println("消费者消费产品"); while(true){ clerk.consumeProduct(); } } } public class TestProduceConsume { public static void main(String[] args) { Clerk clerk = new Clerk(); Producer p1 = new Producer(clerk); Consumer c1 = new Consumer(clerk); Thread tp = new Thread(p1); Thread tc = new Thread(c1); tp.setName("生产者"); tc.setName("消费者"); tp.start(); tc.start(); } }
- wait():当在同步中执行到此方法,则线程必须等待,直至其他线程执行notify()方法将其唤醒。
网友评论