黑马程序员----Java多线程

来源:互联网 发布:海康网络球机接线图 编辑:程序博客网 时间:2024/06/04 19:42

------- android培训、java培训、期待与您交流! ----------


1.概念:

进程:进行中的程序

线程:进程中不同的进行流程(执行路径)

多线程的好处:解决了多部分代码同时运行的问题。

弊端:CPU的切换会导致效率变低。


2.创建线程的两种方式

1)implements Runnable :实现接口,避免了单继承造成的局限性

2)Extends Thread :继承父类

示例:

买票问题。如果采用Extends Thread类来实现,要把票数Num定义成静态字段,造成效率的降低,这时候采用implements Runnable的方式就可以将票数定义成非静态字段。

package com.cn.test;/** * 卖票系统例子区分两种线程创建方式 * 实现方式比继承方式避免了单继承的局限性 */class MyThread extends Thread{//继承方式创建private static int num=1000;//卖票数得静态化    @Overridepublic void run() {    while(true){    if(num>0){    Thread.yield();    System.out.println(Thread.currentThread().getName()+"@@@@@@@"+num--);    }        }}}class MyRunnable implements Runnable{private int num=1000;//实现接口方式,因为共用了一个对象产生线程,所以Num字段不用静态化public void run() {    while(true){    if(num>0){    Thread.yield();    System.out.println(Thread.currentThread().getName()+"@@@@@@@"+num--);    }        }}}public class ConstructTest {public static void createByEtds(){//通过继承Threads类创建对象MyThread mt1=new MyThread();MyThread mt2=new MyThread();mt1.start();mt2.start();}public static void createByIpl(){//实现方式创建MyRunnable mr1=new MyRunnable();new Thread(mr1).start();new Thread(mr1).start();new Thread(mr1).start();new Thread(mr1).start();}public static void main(String[] args) {//createByEtds();//继承方式createByIpl();//实现方式}}



3.线程的安全问题

上述例子会产生零票数与负票数的情况


这是因为在某个线程在执行到Num字段的判断时,cpu的执行权被其他线程抢走,这时候Num字段由于不受保护,会被多线程修改。从而出现了0,-1,-2的情况。

线程安全问题产生的原因:多个线程共享未被保护的数据。解决的办法:给共享资源上一把锁,哪个线程要用,哪个线程拿锁进去用。类比:火车上的卫生间。

同步代码块与同步函数能解决这个问题。

关键字:synchronizied

package com.cn.test;/** * 为了演示synchronized函数与代码块的区别,添加了flag * 同步要两个前提:有两个或以上线程,用的是同一个锁 */class TicketThread implements Runnable {private int num = 1000;public boolean flag = true;public void run() {if (flag) {while (true) {synchronized (this) {//同步代码块相当于一把线程锁,保证资源安全if (num > 0) {try {Thread.sleep(10);} catch (Exception e) {// TODO: handle exception}System.out.println(Thread.currentThread().getName()+ "@@@@@code" + num--);}}}} else {while (true) {show();}}}private synchronized void show() {//synchronized修饰的函数,锁的对象是this指针if (num > 0) {try {Thread.sleep(10);} catch (Exception e) {// TODO: handle exception}System.out.println(Thread.currentThread().getName() + "@@@@@show"+ num--);}}}public class SynchronizedDemo {public static void main(String[] args) {TicketThread th=new TicketThread();new Thread(th).start();try{Thread.sleep(10);}catch (Exception e) {e.printStackTrace();}//第一个线程启动后sleep(10),让后面的线程启动th.flag=false;new Thread(th).start();}}

静态同步代码块用的是改函数所属的字节码文件,即对象.getClass()或类.class()

4.死锁

不同线程相互持有其锁,导致程序不能继续进行


package com.cn.test;/** * 死锁 */class MyDeadLock implements Runnable{private boolean flag=true;MyDeadLock(boolean flag){this.flag=flag;}public void run(){if(flag){while(true){synchronized(Locked.lock1){//同时持有两把锁System.out.println(Thread.currentThread().getName()+"lock1");synchronized(Locked.lock2){//第二把锁System.out.println(Thread.currentThread().getName()+"lock2");}}}}else {while(true){synchronized(Locked.lock2){//第二个线程持有第一个线程的锁System.out.println(Thread.currentThread().getName()+"lock2");synchronized(Locked.lock1){System.out.println(Thread.currentThread().getName()+"lock1");}}}}}}class Locked{public static final Object lock1=new Object();public static final Object lock2=new Object();}public class DeadLock {public static void main(String[] args) {MyDeadLock ml1=new MyDeadLock(true);MyDeadLock ml2=new MyDeadLock(false);new Thread(ml1).start();try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}new Thread(ml2).start();}}



5.线程的生命周期


主要涉及方法:sleep(),wait(),notify(),notifyAll()


例子:生产者与消费者

交替的处理机制:首先立flag=false;没有就让消费者wait,转到生产者,生产者++

再改flag.再唤醒,

flag=false

|--if(flag) flag=true;生产者

|--if(flag) flag=false;消费者

由于多个生产者/消费者时用notify出问题,改用notifyAll

package com.cn.test;class Person {private String name;private String gender;private boolean flag = false;//作为交替,设立flagprivate int num=1;public synchronized void set(String name, String gender) {if (flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}this.name = name;this.gender = gender;num++;System.out.println(Thread.currentThread().getName()+"生产者"+num);flag = true;this.notifyAll();}public synchronized void get() {if (!flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}num--;System.out.println(Thread.currentThread().getName()+"消费者@@"+this.num);flag = false;this.notifyAll();}}class Input implements Runnable {Person p;Input(Person p) {this.p = p;}public void run() {int x = 0;// -------------------循环存while (true) {if (x == 0) {p.set("zhangsan", "nan");} elsep.set("XIAOHONG", "NV");x = (x + 1) % 2;}}}class Output implements Runnable {Person p;Output(Person p) {this.p = p;}public void run() {while (true) {p.get();}}}public class MutilpDemo {public static void main(String[] args) {Person p = new Person();//初始化资源Input in1 = new Input(p);//生产者1线程Input in2 = new Input(p);//生产者2线程Output out1 = new Output(p);//消费者1线程Output out2 = new Output(p);//消费者2线程Thread t1 = new Thread(in1);Thread t2 = new Thread(in1);Thread t3 = new Thread(out1);Thread t4 = new Thread(out1);t1.start();t2.start();t3.start();t4.start();}}


7.JDK1.5以后的新特性

Lock lock=new ReentrantLock();

condition conXX=lock.newCondition()

wait -> conXX.await

notify-> conXX.sign

package com.cn.test;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;class Sourse{private String name;//资源名称private int num;//资源数量private boolean flag=false;//交替旗帜Lock lock=new ReentrantLock();//新的锁Condition conPro=lock.newCondition();//能根据不同条件notify(signal)Condition conCut=lock.newCondition();public void produce(){lock.lock();try {if(flag){try {conPro.await();} catch (InterruptedException e) {e.printStackTrace();}}this.name="货物"+num;this.num++;System.out.println("Sheng生产者"+Thread.currentThread().getName()+this.name);flag=true;conCut.signalAll();} catch (Exception e) {e.printStackTrace();}finally{lock.unlock();//要释放锁}}public void custom(){lock.lock();try {if(!flag){try {conCut.await();} catch (InterruptedException e) {e.printStackTrace();}}this.name="货物"+num;this.num--;System.out.println("消费者"+Thread.currentThread().getName()+this.name);flag=false;conPro.signalAll();} catch (Exception e) {e.printStackTrace();}finally{lock.unlock();}}}class setTread implements Runnable{private Sourse s;setTread(Sourse s){this.s=s;}public void run() {while(true){s.produce();}}}class getTread implements Runnable{private Sourse s;getTread(Sourse s){this.s=s;}public void run() {while(true){s.custom();;}}}public class For15Demo {public static void main(String[] args) {Sourse s=new Sourse();setTread s1=new setTread(s);setTread s3=new setTread(s);getTread s2=new getTread(s);getTread s4=new getTread(s);new Thread(s1).start();new Thread(s2).start();new Thread(s3).start();new Thread(s4).start();}}



8.其他补充

.interrupt()强制唤醒线程,会抛InterruptedException异常

setPriority(0~10)设置优先级

setDeamXX设置守护线程,在jvm运行环境里只剩下守护线程时,程序结束

join()强行并线


0 0