黑马程序员 多线程

发布时间:2017-1-17 14:52:53 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"黑马程序员 多线程",主要涉及到黑马程序员 多线程方面的内容,对于黑马程序员 多线程感兴趣的同学可以参考一下。

-----------android培训、java培训、java学习型技术博客、期待与您交流! ----------- 多线程: 进程:一个正在执行中的程序 线程:进程中的一个独立的控制单元。控制着进程的执行。 一个进程中至少有一个线程。 多线程的机制可以让程序运行地更有效率。 jvm启动的时候会有一个进程java.exe。该进程中至少有一个线程负责java程序的执行。这个线程运行的代码存在于main方法中。该线程称之为主线程。 对线程的操作:(线程的5种状态:被创建,运行,冻结,阻塞(临时状态),消亡) sleep(time)睡眠, wait()等待,notify();唤醒 以上两种方法把线程冻结后(睡眠时间超时或被唤醒),由冻结状态转到临时状态,等待获取CPU运行权限 线程都有自己默认的名称:Thread-编号,编号从0开始。 可以自己设定名称: 1,Thread(String name),构造函数传入名字 2,通过setName()和getName()函数对名字设定或读取。 static Thread currentThread() 返回对当前正在执行的线程对象的引用  创建线程的两种方式: 第一种方式: 继承Thread类,重写public void run()方法,建立子类对象(同时创建一个线程)后,用start()方法启动线程执行run()方法中的内容。 class Demo extends Thread { private static int tick = 60; Demo(String name) { super(name);//调用父类的构造函数。 } public void run() { while (true) { if(tick>0) { System.out.println(Thread.currentThread().getName()+"卖的票"+tick--); } } } } class ThreadDemo { public static void main(String[] args) { Demo d = new Demo();//建立对象的同时也建立了一个进程 d.start();//运行d中的run()方法。 Demo d1 = new Demo("线程1");//自定义线程名称。 Demo d2 = new Demo("线程2"); d1.start(); d2.start(); } } 创建线程的第二种方式: 1,一个类实现Runnable接口,复写void run()方法。 2,建立类对象,将对象传递给Thread建立一个线程对象。 3,调用start方法启动线程,运行run()方法里面的代码。 class Demo2 implements Runnable { private int tick = 60; public void run() { while (true) { if(tick>0) { System.out.println(Thread.currentThread().getName()+"卖的票"+tick--); } } } } class ThreadDemo2 { public static void main(String[] args) { Demo2 d = new Demo2();//创建对象 Thread t1 = new Thread(d);//将对象传入Thread中,建立Thread类 Thread t2 = new Thread(d); Thread t3 = new Thread(d); t1.start();//Thread类启动线程,运行d中的run()方法。 t2.start(); t3.start(); } } 两种创建线程方式的区别: 第一种方式是继承Thread类,就不能再继承其它类。第二种方式可以继承其它类,实现其它接口。 建议使用第二种方式,避免了但继承的局限性。 因为计算机运算机制的原因,多线程会运行会出现安全问题。 解决方式是对多条操作共享数据的语句,只让一个线程执行,执行时,其它线程不可以参与执行。 即线程同步: 1,同步代码块: synchronized(对象(可以是任意对象)) { 需要被同步的代码 } 2,同步函数:用synchronized修饰函数 public synchronized void method() { } 同步的前提: 1,必须要有两个或者两个以上的线程。 2,必须是多个线程使用同一个锁() 同步解决了多线程的安全问题,但是同时降低了代码运行效率。 对于寻找代码中会出现安全代码的小技巧 1:明确哪些代码是多线程运行代码。 2,明确共享数据 3,明确多线程运行代码中哪些语句是操作共享数据的。 同步代码块和函数都是封装代码,同步代码块同步的锁是输入的对象,而函数同步的是this所指对象。 如果同步函数被静态修饰后,因为静态进内存时,内存没有本类对象,但是有该类对应的字节码文件对象:类名.class  该对象的类型是class。所以静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 死锁:同步中嵌套同步。 eg:两个不同的锁,一个线程通过a锁后想要获得b锁,另一个线程通过b锁后想要获得a锁。两线程僵持不下,就锁住了。 class MyLock { static Object locka = new Object(); static Object lockb = new Object(); public static void main(String[] args) { DeadLock dl = new DeadLock(); Thread t1 = new Thread(dl); Thread t2 = new Thread(dl); t1.start(); t2.start(); } } class DeadLock implements Runnable { boolean flag = true; public void run() { if(flag) { flag =false; while(true) { synchronized(MyLock.locka) { System.out.println("locka"); synchronized(MyLock.lockb) { System.out.println("lockb"); } } } } else{ flag = true; while(true) { synchronized(MyLock.lockb) { System.out.println("lockb+++++++"); synchronized(MyLock.locka) { System.out.println("locka+++++++"); } } } } } } 线程间通讯: 多个线程在操作同一个资源。但是资源的动作不同。 为了手动让某一线程暂停或开启,可以使用等待唤醒机制。在同步中使用wait(),notify(),notifyAll()等方法。这些方法在操作同步中的线程时,都必须要标识他们所操作线程持有的锁。只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。 生产者消费者: class ProducerConsumerDemo { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } } class Resource { private String name; private int count = 1; private boolean flag = false; public synchronized void set(String name) { while (flag)//if(flag)只判断一次,会出现多个都线程生产的情况 { try { wait();//线程等待,释放执行权 } catch (Exception e) { } } this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"....生产者"+this.name); flag = true; this.notifyAll();//因为改成while()循环,用notify()会出现全部wait()。 } public synchronized void out() { while(!flag) { try { wait(); } catch (Exception e) { } } System.out.println(Thread.currentThread().getName()+"........消费者"+this.name); flag = false; this.notifyAll(); } } class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while (true) { res.set("商品"); } } } class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { res.out(); } } } jdk1.5以后,用lock锁替换了synchronized,将Object中的wait(),notify(),notifyAll(),替换成了Condition对象。 该对象可以以Lock中的newCondition()方法获取。且一个锁里面可以支持多个Condition 优化后,实现了本方只唤醒对方操作。显式的锁机制,显式的等待唤醒机制。 import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; class ProducerConsumerDemo2 { public static void main(String[] args) { Resource r = new Resource();//创建资源对象 Producer pro = new Producer(r);//创建生产者 Consumer con = new Consumer(r);//创建消费者 //每两个线程操作生产者和消费者 Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } } class Resource { private String name; private int count = 1; private boolean flag = false; private Lock lock =new ReentrantLock();//建立线程锁 private Condition con_pro = lock.newCondition();// private Condition con_con = lock.newCondition();// public void set(String name)throws InterruptedException { lock.lock(); try { while(flag) con_pro.await(); this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"....生产者"+this.name); flag = true; con_con.signal(); } finally { lock.unlock(); } } public void out()throws InterruptedException { lock.lock(); try { while(!flag) con_con.await(); System.out.println(Thread.currentThread().getName()+"........消费者"+this.name); flag = false; con_pro.signal(); } finally { lock.unlock(); } } } class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while (true) { try { res.set("商品"); } catch (InterruptedException e) { } } } } class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { try { res.out(); } catch (InterruptedException e) { } } } } 结束一个线程: 多线程运行的代码通常是循环结束。用标记控制住循环,就可以让run()方法结束,也就导致线程结束。 但是同步中线程都wait()的话,控制住循环也不能结束线程。这个时候用Thread类中的interrupt()方法将冻结中的线程强制唤醒。唤醒的同时会抛出异常。 守护线程(后台线程): Thread类中的void setDaemon(boolean on)方法,将前台线程转换成后台线程。当前台线程都结束时,后台线程也自动结束。该方法需在线程启动前使用。 join()方法:类似插队,A线程执行到了B线程的join()方法,A线程会等待B线程执行完再执行。  public final void join()                 throws InterruptedException等待该线程终止。  抛出: InterruptedException - 如果任何线程中断了当前线程。当抛出该异常时,当前线程的中断状态 被清除。 注意: Thread类中复写了toString()方法,返回该线程的字符串表示形式,包括线程名称、优先级和线程组。 线程组:一般哪个线程开启的新线程,新线程就属于哪个组。 线程优先级:1到10级。线程默认为5级。 级数越高,CPU执行的频率越高 void setPriority(int newPriority) 更改线程的优先级。 eg:new Thread(new Demo()).setPriority(Thread.MAX_PRIORITY); 暂停线程:可以暂缓一下线程的运行,平均下线程运行的概率。 static void yield() 暂停当前正在执行的线程对象,并执行其他线程。  -----------android培训、java培训、java学习型技术博客、期待与您交流! ------------

上一篇:freemarker中空值 null的处理 ?exists ?default("")
下一篇:数据挖掘学习笔记(三)数据预处理

相关文章

相关评论