Day11 /* 进程:是一个正在被执行中的程序。 每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。 线程:就是进程中的一个独立完成控制单元。 线程在控制着进程的执行。 一个进程中至少有一个线程。 创建线程的第一种方式, 继承Thread类 步骤: 1.定义类继承Thread类 2.复写Thread类中的run方法,(目的是将自定义代码存储在run方法中,让线程运行。) 3.实例化定义的类,调用start方法, start方法有两个作用,1)启动线程 2)调用run方法 为什么覆盖run方法呢 Thread类用于描述线程。 该类定义了一个功能,用于存储线程要运行而定代码,该存储功能就是run方法。 也就是说Thread类中的run方法,用于存储线程运行的代码。 */ class D11Demo extends Thread { public void run() { for (int i=0;i<100;i++ ) { System.out.println("---demo run---"+i); } } } class D11TheradDemo { public static void main(String[] args) { Demo d = new Demo(); d.start();//开启线程并执行该线程的run方法。 d.run();//仅仅是对象的函数调用,而线程创建了,并没有运行。 // for (int i=0;i<100;i++ ) { System.out.println("---mian run---"+i); } } } /* 练习: 创建两个线程和主线程交替运行 通过 this.getName()或Thread.currentThread() 方法可以获取线程名称 */ class D11Test1 extends Thread { public void run() { for (int i=0;i<30;i++ ) { System.out.println(getName()+"---run---"+i); } } } class D11Test2 extends Thread { public void run() { for (int i=0;i<30;i++ ) { System.out.println(getName()+"---run---"+i); } } } class D11Test3 extends Thread { public void run() { for (int i=0;i<30;i++ ) { System.out.println(getName()+"---run---"+i); } } } class D11TheradTestDemo { public static void main(String[] args) { D11Test1 t1 = new D11Test1(); t1.start(); D11Test2 t2 = new D11Test2(); t2.start(); D11Test3 t3 = new D11Test3(); t3.start(); for (int i=0;i<30;i++ ) { System.out.println("---mian run---"+i); } } } /* 练习2 需求:简单的买票程序。 多个窗口同时买票。 创建线程的第二种方法,实现 Runnable 接口 步骤 1.定义类实现Runnable接口 2.覆盖Runnable接口中的run方法。 将线程要运行的代码存放在run方法中) 3.通过Thread类建立线程对象。 4.将Runnable接口的子类对象作为实际参数给Thread类的构造函数。 自定义的run方法所属的对象时Runnable接口的子类对象,所以要让线程调用指定对象的run方法,就必须明确该run方法的对象。 5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。 两种方式的区别: Runnable方式: 1.避免的单继承的局限性,在定义线程是建议使用该方式。 2.线程代码存在Runnable子类的run方法中 继承Thread方式: 1.有局限性,因为Java的单继承特性如果继承可Thread类限制了继承其他类。 2.线程带代码存放在Thread子类的run方法中。 */ class D11Ticket implements Runnable//Thread { private int tick = 100; public void run() { while(true) { if(tick >0) { /* try { Thread.sleep(10); } catch (Exception e) { } */ /* 通过上面代码 Thread.sleep(10); 分析发现 打印出 0 -1 -2 等错票 多线程的运行出现的安全问题。 问题的原因: 当多条语句在操作同一个线程共享数据时, 一个线程对多条语句执行了一部分,还没有执行完毕时, 另一个线程参与进来执行,导致共享数据的错误。 解决方法: 对于多条操作的共享数据的语句,只能让一个线程都执行完毕。 在一个线程执行过程中,其他线程不可以参与执行。 Java对于多线程的安全问题提供了一个同步代码块用于解决这种问题。 格式如下: synchronized(对象) { } */ System.out.println(Thread.currentThread().getName()+" Sale :"+ tick --); } } } } class D11TicketDemo { public static void main(String[] args) { D11Ticket t1 = new D11Ticket(); new Thread(t1).start(); new Thread(t1).start(); new Thread(t1).start(); new Thread(t1).start(); } } /* Java对于多线程的安全问题提供了一个同步代码块用于解决这种问题。 格式如下: synchronized(对象) { } 对象如同锁,持有锁的线程可以再同步中执行, 没有持有锁的线程即使获取到CPU的执行权,也进不去,因为没有锁。 同步的前提: 1.必须要有两个或者两个以上的线程。 2.必须是多个线程使用同一个锁。 同步的利弊: 利:保证只用一个线程在执行,解决了多线程中多条语句在操作同一个线程共享数据时的安全问题。 弊:多个线程都需要判断锁,较为消耗资源。 */ class D11Ticket2 implements Runnable//Thread { private int tick = 100; Object obj = new Object(); public void run() { while(true) { synchronized(obj) { if(tick >0) { try { Thread.sleep(10); } catch (Exception e) { } // System.out.println(Thread.currentThread().getName()+" Sale :"+ tick --); } } } } } class D11TicketDemo2 { public static void main(String[] args) { D11Ticket2 t1 = new D11Ticket2(); new Thread(t1).start(); new Thread(t1).start(); new Thread(t1).start(); new Thread(t1).start(); } } /* 练习3 需求: 银行有一个金库 有两个存户分别存300斤黄金,每次存100斤,存3次。 目的: 该程序是否有安全问题,如果有,如何解决? 如何找问题: 1.明确哪些代码是多线程执行代码。 2.明确哪些是共享数据。 3.明确多线程运行代码中哪些语句是操作共享数据的。 */ class D11Bank { private int sum; //同步函数也可以解决这种问题。 public synchronized void add(int n) { sum +=n; // try{Thread.sleep(1000);}catch (Exception e){} System.out.println("sum="+ sum); } } class D11Cus implements Runnable { private D11Bank b = new D11Bank(); public void run() { for(int i =0; i<3 ;i++ ) { b.add(100); } } } class D11BankDemo { public static void main(String[] args) { D11Cus c = new D11Cus(); // Thread t1 = new Thread(c); Thread t2 = new Thread(c); // t1.start(); t2.start(); } } /* 同步函数用的是哪一个锁呢? 函数需要被对象调用,那么函数都有一个所属对象引用,就是this。 所以同步函数使用的锁是this 下面通过该程序进行验证: 使用线程来卖票 一个线程在同步代码中,一个线程在同步函数中。 都在执行卖票动作 */ class D11Ticket3 implements Runnable//Thread { private int tick = 100; Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(this) { if(tick >0) { try{Thread.sleep(10);}catch (Exception e){} // System.out.println(Thread.currentThread().getName()+" code Sale :"+ tick --); } } } } else { while(true) { show(); } } } public synchronized void show() { if(tick >0) { try{Thread.sleep(10);}catch (Exception e){} // System.out.println(Thread.currentThread().getName()+" function Sale :"+ tick --); } } } class D11TicketDemo3 { public static void main(String[] args) { D11Ticket3 t = new D11Ticket3(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); // t1.start(); try{Thread.sleep(10);}catch (Exception e){} t.flag =false; t2.start(); } } /* 如果同步函数被static修饰后,使用的锁是什么呢? 静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。 类名.class 该对象的类型是Class 所以 静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class */ class D11Ticket4 implements Runnable//Thread { private static int tick = 100; Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { //synchronized(obj) synchronized(D11Ticket4.class) { if(tick >0) { try{Thread.sleep(20);}catch (Exception e){} // System.out.println(Thread.currentThread().getName()+" code Sale :"+ tick --); } } } } else { while(true) { show(); } } } public static synchronized void show() { if(tick >0) { try{Thread.sleep(10);}catch (Exception e){} // System.out.println(Thread.currentThread().getName()+" function Sale :"+ tick --); } } } class D11TicketDemo4 { public static void main(String[] args) { D11Ticket4 t = new D11Ticket4(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); // t1.start(); try{Thread.sleep(10);}catch (Exception e){} t.flag =false; t2.start(); } } /* 重提 单例设计模式 */ /* //饿汉式 class Single { private static final Single s =new Single(); private Single(); public static Single getInstance() { return s; } } */ //懒汉式 class D11Single { private static D11Single s =null; private D11Single(){} public static D11Single getInstance() { //双重判断 if(s == null) { synchronized(D11Single.class) { if(s == null) { s = new D11Single(); } } } return s; } } /* 死锁 同步中嵌套同步 */ class D11Ticket5 implements Runnable//Thread { private static int tick = 100; Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(D11Ticket4.class) { show(); } } } else { while(true) { show(); } } } public static synchronized void show() { synchronized(D11Ticket4.class) { if(tick >0) { try{Thread.sleep(20);}catch (Exception e){} // System.out.println(Thread.currentThread().getName()+" code Sale :"+ tick --); } } } } class D11TicketDemo5 { public static void main(String[] args) { D11Ticket5 t = new D11Ticket5(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); // t1.start(); try{Thread.sleep(10);}catch (Exception e){} t.flag =false; t2.start(); } } class D11TestLock implements Runnable { private boolean flag; D11TestLock(boolean flag) { this.flag = flag; } public void run() { if(flag) { synchronized(D11MyLock.locka) { System.out.println("if locka"); synchronized(D11MyLock.lockb) { System.out.println("if lockb"); } } } else { System.out.println("else lockb"); synchronized(D11MyLock.lockb) { synchronized(D11MyLock.locka) { System.out.println("else locka"); } } } } } class D11MyLock { static Object locka = new Object(); static Object lockb = new Object(); } class D11DeadLockTest { public static void main(String[] args) { Thread t1 = new Thread(new D11TestLock(true)); Thread t2 = new Thread(new D11TestLock(false)); // t1.start(); t2.start(); } } Day12 /* 线程间通讯 其实就是多个线程在操作同一个资源 但是操作的动作不同 wait();线程存储在线程池中 notify();唤醒线程池中的线程,通常唤醒顶部的线程。 notifyAll();;唤醒线程池中所有的线程 这些作线程的方法要使用在同步中,因为要对持有监视器(锁)的线程操作。 所以要使用在同步中,因为只有同步才具有锁。 为什么这些操作线程的方法要定义在Object类中呢? 因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁。 只有同一个锁上的被wait()的线程,才可以被同一个锁上的notify()唤醒线程,不可以对不同锁中的线程进行唤醒。 (也就是说,等待和唤醒线程的必须是同一个锁。) 因为锁可以使任意对象,所以可以被任意对象调用的方法只能有Object,所以定义在Object类中。 */ import java.util.concurrent.locks.*; class D12Res { String name; String sex; boolean flag = false; } class D12Input implements Runnable { private D12Res r; D12Input(D12Res r) { this.r = r ; } public void run() { int i=0; while(true) { synchronized(r) { if(r.flag) try{r.wait();}catch (Exception e){} if(i%2==0) { r.name ="tom"; r.sex = "man"; } else { r.name ="赫尔"; r.sex = "女"; } i++; r.flag =true; //唤醒OutPut r.notify(); } } } } class D12Output implements Runnable { private D12Res r; D12Output(D12Res r) { this.r = r ; } public void run() { while(true) { synchronized(r) { if(!r.flag) try{r.wait();}catch (Exception e){} System.out.println(r.name+" "+r.sex); // r.flag =false; r.notify(); } } } } class D12InPutAndOutPutDemom { public static void main(String[] args) { D12Res r = new D12Res(); D12Input in = new D12Input(r); D12Output out = new D12Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } } /* 改进D12Res */ class D12Res2 { private String name; private String sex; private boolean flag = false; public synchronized void set(String name, String sex ) { if(flag) try{this.wait();}catch (Exception e){} this.name = name ; this.sex = sex; flag = true; this.notify(); } public synchronized void out() { if(!flag) try{this.wait();}catch (Exception e){} System.out.println(this.name+" "+this.sex); flag = false; this.notify(); } } class D12Input2 implements Runnable { private D12Res2 r; D12Input2(D12Res2 r) { this.r = r ; } public void run() { int i=0; while(true) { if(i%2==0) r.set("tom" ,"man"); else r.set("赫尔" ,"女"); i++; } } } class D12Output2 implements Runnable { private D12Res2 r; D12Output2(D12Res2 r) { this.r = r ; } public void run() { while(true) { r.out(); } } } class D12InPutAndOutPutDemom2 { public static void main(String[] args) { D12Res2 r = new D12Res2(); new Thread(new D12Input2(r)).start(); new Thread(new D12Output2(r)).start(); } } class D12Resource { private String name; private int num =1; private Boolean flag = false; public synchronized void set(String name) { if(flag) try{this.wait();}catch (Exception e){} this.name = name + "..." + num++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag =true; this.notify(); } public synchronized void out() { if(!flag) try{this.wait();}catch (Exception e){} System.out.println(Thread.currentThread().getName()+".........消费者........."+this.name); flag =false; this.notify(); } } class D12Producer implements Runnable { private D12Resource res; D12Producer(D12Resource res) { this.res = res; } public void run() { while(true) res.set("商品"); } } class D12Consumer implements Runnable { private D12Resource res; D12Consumer(D12Resource res) { this.res = res; } public void run() { while(true) res.out(); } } class D12ResourceDemo { public static void main(String[] args) { D12Resource r = new D12Resource(); D12Producer pro = new D12Producer(r); D12Consumer con = new D12Consumer(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(pro); Thread t4 = new Thread(pro); Thread t5 = new Thread(con); Thread t6 = new Thread(con); Thread t7 = new Thread(con); Thread t8 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); t7.start(); t8.start(); /* 运行后会发现存在生产一个消费多个或生产多个消费单个(有些生产被无视)的异常。 运行异常如下: Thread-2...生产者...商品...123 Thread-3...生产者...商品...133 Thread-4.........消费者.........商品...133 Thread-2...生产者...商品...134 Thread-4.........消费者.........商品...134 ... ... ... ... ... Thread-0...生产者...商品...1453 Thread-4.........消费者.........商品...1453 Thread-1...生产者...商品...1454 Thread-2...生产者...商品...1455 Thread-5.........消费者.........商品...1455 Thread-6.........消费者.........商品...1455 Thread-7.........消费者.........商品...1455 Thread-8.........消费者.........商品...1455 E:\ProgramCode\Java\JAVA毕向东> */ } } /* 运行后会发现存在消费多个或生产多个的异常。 产生问题的原因是: 线程在被唤醒的时候没有判断自己有没有是否具备执行生产或消费。从而导致消费多个或生产多个。 即生产线程被生产线程唤醒,其余消费被等待的时候,唤醒的生产线程所做的生产会覆盖前一个生产线程的生产,这样大的生产是不合法的。 解决办法: 线程被唤醒后,判断是否具备执行。(if 改为 while) 不过执行到一定时间后,容易出现只唤醒本方线程的情况,导致程序中的所有线程都处于等待状态。 解决办法: notify 改为 notifyAll 这样就可以解决这个问题了。对于多个生产者和消费者适用于这样的方法。 为什么定义while判断标记? 因为让被唤醒的线程再一次判断标记,防止出错。 为什么定义为notifyAll? 1.因为需要唤醒对方线程 2.因为只用notify,容易出现只唤醒本方线程的情况,导致程序中的所有线程都等待。 */ class D12Resource2 { private String name; private int num =1; private Boolean flag = false; public synchronized void set(String name) { while(flag) try{this.wait();}catch (Exception e){} this.name = name + "..." + num++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag =true; this.notifyAll(); } public synchronized void out() { while(!flag) try{this.wait();}catch (Exception e){} System.out.println(Thread.currentThread().getName()+".........消费者........."+this.name); flag =false; this.notifyAll(); } } class D12Producer2 implements Runnable { private D12Resource2 res; D12Producer2(D12Resource2 res) { this.res = res; } public void run() { while(true) res.set("商品"); } } class D12Consumer2 implements Runnable { private D12Resource2 res; D12Consumer2(D12Resource2 res) { this.res = res; } public void run() { while(true) res.out(); } } class D12ResourceDemo2 { public static void main(String[] args) { D12Resource2 r = new D12Resource2(); D12Producer2 pro = new D12Producer2(r); D12Consumer2 con = new D12Consumer2(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(pro); Thread t4 = new Thread(pro); Thread t5 = new Thread(con); Thread t6 = new Thread(con); Thread t7 = new Thread(con); Thread t8 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); t7.start(); t8.start(); } } /* JDK5.0升级 改版生产者消费者 换型 */ class D12Resource3 { private String name; private int num =1; private Boolean flag = false; // private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void set(String name) throws InterruptedException { lock.lock(); try { while(flag) condition.await(); this.name = name + "..." + num++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag =true; condition.signalAll(); } finally { lock.unlock(); } } public void out() throws InterruptedException { lock.lock(); try { while(!flag) condition.await(); System.out.println(Thread.currentThread().getName()+".........消费者........."+this.name); flag =false; condition.signalAll(); } finally { lock.unlock(); } } } class D12Producer3 implements Runnable { private D12Resource3 res; D12Producer3(D12Resource3 res) { this.res = res; } public void run() { while(true) { try { res.set("商品"); } catch (InterruptedException e) { } } } } class D12Consumer3 implements Runnable { private D12Resource3 res; D12Consumer3(D12Resource3 res) { this.res = res; } public void run() { while(true) { try { res.out(); } catch (InterruptedException e) { } } } } class D12ResourceDemo3 { public static void main(String[] args) { D12Resource3 r = new D12Resource3(); D12Producer3 pro = new D12Producer3(r); D12Consumer3 con = new D12Consumer3(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(pro); Thread t4 = new Thread(pro); Thread t5 = new Thread(con); Thread t6 = new Thread(con); Thread t7 = new Thread(con); Thread t8 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); t7.start(); t8.start(); } } /* 改进升级版生产者消费者 定义一两个Condition:condition_pro condition_con 生产者线程等待,唤醒消费者等待线程 消费者线程等待,换型生产者等待线程 即本方线程只唤醒对方线程的操作。 JDK1.5 中提供了多线程的升级解决方案。 1.将同步 synchronized 替换为 Lock 操作 2.将Object中的 wait,notify,notifyAll 替换为condiction 对象,该对象可以对 Lock锁 进行获取 */ class D12Resource4 { private String name; private int num =1; private Boolean flag = false; // private Lock lock = new ReentrantLock(); private Condition condition_pro = lock.newCondition(); private Condition condition_con = lock.newCondition(); public void set(String name) throws InterruptedException { lock.lock(); try { while(flag) condition_pro.await(); this.name = name + "..." + num++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag =true; condition_con.signalAll(); } finally { lock.unlock(); } } public void out() throws InterruptedException { lock.lock(); try { while(!flag) condition_con.await(); System.out.println(Thread.currentThread().getName()+".........消费者........."+this.name); flag =false; condition_pro.signalAll(); } finally { lock.unlock(); } } } class D12Producer4 implements Runnable { private D12Resource4 res; D12Producer4(D12Resource4 res) { this.res = res; } public void run() { while(true) { try { res.set("商品"); } catch (InterruptedException e) { } } } } class D12Consumer4 implements Runnable { private D12Resource4 res; D12Consumer4(D12Resource4 res) { this.res = res; } public void run() { while(true) { try { res.out(); } catch (InterruptedException e) { } } } } class D12ResourceDemo4 { public static void main(String[] args) { D12Resource4 r = new D12Resource4(); D12Producer4 pro = new D12Producer4(r); D12Consumer4 con = new D12Consumer4(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(pro); Thread t4 = new Thread(pro); Thread t5 = new Thread(con); Thread t6 = new Thread(con); Thread t7 = new Thread(con); Thread t8 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); t7.start(); t8.start(); } }
时间: 2024-10-03 13:39:53