线程:是进程的一部分
---实现多线程的两种方式
---创建一个类实现Runnable接口,以这个类的对象作为创建Thread类的对象的构造函数的参数
---直接继承Thread类,重写run方法
---在main函数中有t.join()---即等线程t结束后,当前线程(main)才能执行
---Thread.yeild()---主动放弃CPU的使用权进入ready状态
---设置优先级---t.setPriority()---参数为Thread.MAX_PRIORITY--最高优先级;MIN_PRIORITY---最低优先级
---守护线程---在没有用户线程时,自动离开,这个线程有最低的优先级
eg: java垃圾回收线程---当我们的程序不再有运行中的Thread,程序就不会产生垃圾,当成为虚 拟机上仅剩的线程时 ,java虚拟机会自动离开---运行后台的一种特殊线程---不依赖线程,依 赖系统
t.setDaemon(true)--设置t线程为守护线程
---同步块---eg:多个线程共享同一数据的问题---每个对象对应一把锁
package guo; public class A { public static void main(String[] args) { Object resource=new Object(); MyThread mt1=new MyThread(resource,"MT1"); MyThread mt2=new MyThread(resource,"MT2"); mt1.start(); mt2.start(); } } //自定义的线程类 class MyThread extends Thread{ private Object resource; public MyThread(){} public MyThread(Object resource,String name){ this.resource=resource; this.setName(name); } public void run(){ synchronized(resource){//同步语句块 System.out.println(this.getName()+"线程访问了资料!!!"); System.out.println(this.getName()+"线程带着锁睡觉去了!!!"); try{ Thread.sleep(5000);//睡5000ms后醒来 }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(this.getName()+"线程带着锁睡醒后释放了锁!!!"); } } } /** * 此程序运行的结果为: * MT1线程访问了资料!!! * MT1线程带着锁睡觉去了!!! * MT1线程带着锁睡醒后释放了锁!!! * MT2线程访问了资料!!! * MT2线程带着锁睡觉去了!!! * MT2线程带着锁睡醒后释放了锁!!! */
---同步函数---每个类的实例对应一把锁---方法一旦执行就独占锁---静态方法用的锁是该方法所属类的字节码对 象上的锁
package guo; public class Single1 { public static void main(String[] args) { A2 a = new A2(); Thread t1 = new Thread(a); Thread t2 = new Thread(a); t1.start(); t2.start(); } } class A2 implements Runnable { int i; @Override public void run() { doSomeThing(); } /*同步函数一样是需要获取一把钥匙,该钥匙是哪个对象的呢?*/ public synchronized void doSomeThing() { for (int j = 1; j <= 10; j++) { int h = i + 1; try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } i = h; System.out.println(i); } } }
---通过管道流的方式---简单、效率低,复杂数据和对象不好处理
package guo; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.Random; public class Single2 { public static void main(String[] args) { try { PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(in); PipedSend send = new PipedSend(out); PipedRec rec = new PipedRec(in); Thread t1 = new Thread(send); Thread t2 = new Thread(rec); t1.start(); t2.start(); } catch (Exception e) { e.printStackTrace(); } } } class PipedSend implements Runnable { OutputStream out; public PipedSend(OutputStream out) { this.out = out; } @Override public void run() { for (int i = 1; i <= 5; i++) { byte theValue = (byte) new Random().nextInt(256); try { out.write(theValue); System.out.println("send the value is:" + theValue); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class PipedRec implements Runnable { InputStream in; public PipedRec(InputStream in) { this.in = in; } @Override public void run() { for (int i = 1; i <= 5; i++) { try { byte theValue = (byte) in.read(); System.out.println("receive the value is:" + theValue); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /** * 运行结果是: * send the value is:61 * send the value is:17 * send the value is:63 * send the value is:-81 * send the value is:94 * receive the value is:61 * receive the value is:17 * receive the value is:63 * receive the value is:-81 * receive the value is:94 */
---生产者和消费者---用yeild方法处理---不叫耗资源、安全性低
package guo; import java.util.Random; public class Demo11 { public static void main(String[] args) { FlagSend send = new FlagSend(); FlagRec rec = new FlagRec(send); Thread t1 = new Thread(send); Thread t2 = new Thread(rec); t2.setDaemon(true); t1.start(); t2.start(); } } //生产者 class FlagSend implements Runnable{ boolean flag; int theValue; @Override public void run() { for(int i = 0; i < 5;i++){ while(flag){ Thread.yield(); } theValue = new Random().nextInt(1000); flag = true; System.out.println("send the value is:"+theValue); } } } //消费者---->把生产的对象作为自己的成员 class FlagRec implements Runnable{ FlagSend send; public FlagRec(FlagSend send){ this.send = send; } @Override public void run() { while(true){//死循环 while(!send.flag){ Thread.yield(); } System.out.println("receiver the value is:"+send.theValue); send.flag = false; } } }
---wait notify来交互
这两个方法不是线程的方法,是Object类的方法,每个对象上都可以拥有一个线程等待池,挂在这个对象 上的线程,就可以通过这个对象去让线程等待和唤醒,wait和notify必须放在同步块中
package guo; import java.util.Random; public class WaitTest { public static void main(String[] args) { WaitSend send = new WaitSend(); WaitRec rec = new WaitRec(send); Thread t1 = new Thread(send); Thread t2 = new Thread(rec); t2.setDaemon(true); t1.start(); t2.start(); } } //生产者 class WaitSend implements Runnable{ boolean flag; int theValue; @Override public void run() { for(int i = 1; i <= 5;i++){ synchronized (this) {//wait notify 必须放入同步块 while(flag){//while循环 而不是if 存在虚假唤醒 try { this.wait();//wait方法会释放钥匙 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /*制造食物*/ theValue = new Random().nextInt(10000); System.out.println("send the value is:"+theValue); /*让自己进入阻塞*/ flag = true; /*唤醒该对象上其它等待线程*/ this.notify(); } } } } /*生产者线程和消费者线程 的等待和唤醒必须通过同一个对象 * 同步块必须使用同一个锁同一把钥匙 */ class WaitRec implements Runnable{ WaitSend send; public WaitRec(WaitSend send){ this.send = send; } @Override public void run() { while(true){ synchronized (send) { while(!send.flag){ try { send.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /*消费食物*/ System.out.println("receiver theValue is:"+send.theValue); /*自己进入阻塞状态*/ send.flag = false; /*唤醒生产者*/ send.notify(); } } } }