JavaSE基础复习六:多线程
2012-12-13 22:00
225 查看
------- android培训、java培训、期待与您交流! ----------
1、定义一个类继承Thread类。
2、覆盖Thread类中的run方法。
3、直接创建Thread的子类对象创建线程。
4、调用start方法开启线程并调用线程的任务run方法执行。
通过getName()方法获取线程名,默认名称:Thread-编号(从0开始)
2、覆盖接口的run()方法,将线程的任务代码封装到run()方法中。
3、创建Thread对象,将Runnable接口的子类对象作为Thread类构造函数的参数传递。
4、调用Thread对象的start()方法开启线程。
Thread :如果没有父类可以继承Thread
Runnable :避免了单继承的局限性,建议采用实现接口方式创建线程
2、操作共享数据的代码有多条代码。
在一个线程操作的过程中,其他线程可以参与进来。
同步函数:锁其实是this;
静态同步函数:锁是 类名.class 它是一个Class类的字节码文件对象
举例:火车上的卫生间
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。
同步的前提:有多个线程并使用同一个锁。
饿汉式:对象在类进入内存中时加载。不存在线程安全的问题
懒汉式:对象延迟加载。使用同步代码块,锁是类名.class,并在锁外在进行一次判断(双层判断)。可以防止加锁浪费资源。
wait();notify();notifyAll(); 这些方法都应该在同步代码中使用,对持有锁的线程进行操作。
这些方法都定义在Object类中,所有对象都可以是锁,这些方法只能唤醒或者等待持有相同锁的线程。
新特性,多线程的升级解决方案,将同步的synchronized 升级为显示的lock(接口),
将wait(),notify(),notifyAll()升级为condition对象,该对象可以通过lock锁获取。
可以实现只唤醒对方的操作。
2、如果线程处于等待(冻结)状态,无法结束线程,可以使用interrupt()方法强制解除冻结状态,进入运行状态,这样就可以操作标记,结束线程。
1、wait()为Object的方法,sleep()为Thread的方法
2、wait()必须有锁
3、wait()需要notify()唤醒,sleep()时间到了自动获取CPU执行资格
setDaemon();守护进程,前台结束就结束
Thread类的 toString()方法,返回 [程名称,优先级,线程组]
setPriority()设置优先级 MAX_PRIORITY MIN_PRIORITY NORMAL_PRIORITY setName()
yield();静态方法:暂停当前线程执行
创建线程两种方法:继承Thread类或者实现Runnable接口
一:继承Thread类。
步骤:1、定义一个类继承Thread类。
2、覆盖Thread类中的run方法。
3、直接创建Thread的子类对象创建线程。
4、调用start方法开启线程并调用线程的任务run方法执行。
通过getName()方法获取线程名,默认名称:Thread-编号(从0开始)
二:实现Runnable接口。
1、定义类实现Runnable接口。2、覆盖接口的run()方法,将线程的任务代码封装到run()方法中。
3、创建Thread对象,将Runnable接口的子类对象作为Thread类构造函数的参数传递。
4、调用Thread对象的start()方法开启线程。
Thread :如果没有父类可以继承Thread
Runnable :避免了单继承的局限性,建议采用实现接口方式创建线程
线程安全问题产生原因:
1、多个线程操作共享数据时。2、操作共享数据的代码有多条代码。
在一个线程操作的过程中,其他线程可以参与进来。
线程状态转换
synchronized 同步锁:
同步代码块:锁是一个对象;同步函数:锁其实是this;
静态同步函数:锁是 类名.class 它是一个Class类的字节码文件对象
/* 卖票程序 同步代码块形式 */ class Ticket implements Runnable { //接口没有抛出异常,所以run()方法内只能捕捉异常 private int num = 100; Object obj = new Object(); public void run() { while(true) { try{ Thread.sleep(100);//---测试多线程调用时,数据num出现负数 }catch(InterruptedException e) { System.out.println("线程出错了"); } synchronized(obj){ if(num>0){ System.out.println(Thread.currentThread().getName() + "----- sale ----" + num--); } } } } } class TicketDemo { public static void main(String[] args) { Ticket t = new Ticket();//---只有一个Ticket对象 Thread t1 = new Thread(t); // Thread t2 = new Thread(new Ticket()); // Thread t3 = new Thread(new Ticket()); // Thread t4 = new Thread(new Ticket()); //---4个Ticket对象需要使用static修饰num Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); }
举例:火车上的卫生间
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。
同步的前提:有多个线程并使用同一个锁。
单例设计模式:
使类只有一个对象(构造函数私有化,在类中创建本类对象并私有化为静态,定义公共静态方法,通过调用返回对象)饿汉式:对象在类进入内存中时加载。不存在线程安全的问题
懒汉式:对象延迟加载。使用同步代码块,锁是类名.class,并在锁外在进行一次判断(双层判断)。可以防止加锁浪费资源。
/* 多线程下的单例设计模式 */ //---饿汉式 class SingleHg { private static final SingleHg s = new SingleHg(); private SingleHg(){} public static SingleHg getInstance(){ return s; } } //---懒汉式 class SingleLz { private static SingleLz s = null; private SingleLz(){} public static SingleLz getInstance(){ if(s==null) s = new SingleLz(); return s; } } //---加同步锁的懒汉式,面试常考,一般实际用饿汉式 class Single { private static Single s = null; private Single(){} public static /*synchronized*/ Single getInstance(){ //---使用同步函数会降低效率,每次都要获取锁 if(s==null) synchronized(Single.class){ if(s==null) s = new Single(); } return s; } }
死锁程序:
Interrupt();强制清除线程的冻结状态,使线程获取执行资格,但是会使线程抛出InterruptedException线程间通信:其实是多个线程在操作同一个资源,只是操作的动作不同;
考虑同步问题,加入等待唤醒机制;wait() notify()wait();notify();notifyAll(); 这些方法都应该在同步代码中使用,对持有锁的线程进行操作。
这些方法都定义在Object类中,所有对象都可以是锁,这些方法只能唤醒或者等待持有相同锁的线程。
生产者消费者问题:
多个生产者消费者,需要用while()循环判断标记;class Duck { private int id; Duck(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "Duck [id=" + id + "]"; } } class DuckBasket { int index = 0; Duck[] ducks = new Duck[5]; public synchronized void push(Duck duck) { while(index==ducks.length) try { System.out.println(Thread.currentThread().getName()+":篮子满了,歇会~~~~~~~~~!"); this.wait(); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } ducks[index] = duck; System.out.println(Thread.currentThread().getName()+"生产了"+duck); index++; notify(); } public synchronized Duck pop() { while(index==0) try { System.out.println(Thread.currentThread().getName()+":空了,快生产烤鸭!"); wait(); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } index--; //---打印输出用到了共享数据,要放到同步代码中 System.out.println(Thread.currentThread().getName()+"消费了"+ducks[index]); notify(); return ducks[index]; } } class Producer implements Runnable { DuckBasket db; public Producer(DuckBasket db) { super(); this.db = db; } @Override public void run() { for(int i=0; i<20; i++) { Duck duck = new Duck(i); db.push(duck); } } } class Consumer implements Runnable { DuckBasket db; public Consumer(DuckBasket db) { super(); this.db = db; } @Override public void run() { for(int i=0; i<20; i++) { db.pop(); } } } public class ProducerConsumerDemo { /** * @param args */ public static void main(String[] args) { DuckBasket db = new DuckBasket(); Producer pro1 = new Producer(db); Consumer con1 = new Consumer(db); Thread t1 = new Thread(pro1,"生产者----1"); Thread t2 = new Thread(con1,"消费者1"); Thread t3 = new Thread(pro1,"生产者----2"); Thread t4 = new Thread(con1,"消费者2"); t1.start(); t2.start(); t3.start(); t4.start(); } }
新特性,多线程的升级解决方案,将同步的synchronized 升级为显示的lock(接口),
将wait(),notify(),notifyAll()升级为condition对象,该对象可以通过lock锁获取。
可以实现只唤醒对方的操作。
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Duck { private int id; Duck(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "Duck [id=" + id + "]"; } } class DuckBasket { int index = 0; Duck[] ducks = new Duck[5]; Lock lock = new ReentrantLock(); Condition proL = lock.newCondition(); Condition conL = lock.newCondition(); public void push(Duck duck) { lock.lock(); try{ while(index==ducks.length) try { System.out.println(Thread.currentThread().getName()+":篮子满了,歇会~~~~~~~~~!"); proL.await(); } catch (InterruptedException e) { e.printStackTrace(); } ducks[index] = duck; System.out.println(Thread.currentThread().getName()+"做了"+duck); index++; conL.signal(); }finally{ lock.unlock(); } } public Duck pop() { lock.lock(); try { while(index==0) try { System.out.println(Thread.currentThread().getName()+":空了,快做烤鸭!"); conL.await(); } catch (InterruptedException e) { e.printStackTrace(); } index--; //---打印输出用到了共享数据,要放到同步代码中 System.out.println(Thread.currentThread().getName()+"消费了"+ducks[index]); proL.signal(); return ducks[index]; } finally{ lock.unlock(); } } } class Producer implements Runnable { DuckBasket db; public Producer(DuckBasket db) { super(); this.db = db; } @Override public void run() { for(int i=0; i<20; i++) { Duck duck = new Duck(i); db.push(duck); } } } class Consumer implements Runnable { DuckBasket db; public Consumer(DuckBasket db) { super(); this.db = db; } @Override public void run() { for(int i=0; i<20; i++) { db.pop(); } } } public class ProConLock { /** * @param args */ public static void main(String[] args) { DuckBasket db = new DuckBasket(); Producer pro1 = new Producer(db); Consumer con1 = new Consumer(db); Thread t1 = new Thread(pro1,"生产者----1"); Thread t2 = new Thread(con1,"消费者1"); Thread t3 = new Thread(pro1,"生产者----2"); Thread t4 = new Thread(con1,"消费者2"); t1.start(); t2.start(); t3.start(); t4.start(); }
如何停止线程?
1、控制循环,做一个标记,使标记改变时满足条件就停止循环,结束run()方法;2、如果线程处于等待(冻结)状态,无法结束线程,可以使用interrupt()方法强制解除冻结状态,进入运行状态,这样就可以操作标记,结束线程。
wait()和sleep()相同点,都可以使线程进入冻结状态,都抛出异常。
区别:1、wait()为Object的方法,sleep()为Thread的方法
2、wait()必须有锁
3、wait()需要notify()唤醒,sleep()时间到了自动获取CPU执行资格
其他方法
join()方法,当a线程执行到了b线程的join方法时,a等待b执行完在继续执行。setDaemon();守护进程,前台结束就结束
Thread类的 toString()方法,返回 [程名称,优先级,线程组]
setPriority()设置优先级 MAX_PRIORITY MIN_PRIORITY NORMAL_PRIORITY setName()
yield();静态方法:暂停当前线程执行
匿名内部类创建进程---常用。
------- android培训、java培训、期待与您交流! ----------相关文章推荐
- javase复习整理(一):基础要点、重点、易错点、多线程梳理总结
- JavaSE复习之三 基础知识:常用API
- JavaSE复习之二 基础知识:面向对象 补充(4)
- javase基础复习攻略《三》
- javase基础复习攻略《四》
- javase基础复习攻略《九》
- 黑马程序员--JAVA基础复习之多线程(三)线程间通信 生产者消费者
- Java复习第二天---JavaSE基础
- 黑马程序员--java基础复习之多线程及线程间通信
- JavaSE基础复习:面向对象知识点二
- JavaSE基础复习四:常用类笔记
- JavaSE复习之四 基础知识:集合
- 黑马程序员——javase基础--多线程
- JavaSE复习之一 基础知识:Java的基础语法 补充(3)
- JavaSE复习之二 基础知识:面向对象 补充(6)
- JavaSE复习之三 基础知识:常用API
- javase重新开始系列之多线程基础
- JavaSE复习之五 基础知识:接口
- JavaSE复习之二 基础知识:面向对象
- JavaSE复习之三 基础知识:常用API 补充(1)