首页 > 代码库 > j2ee(5) 线程
j2ee(5) 线程
1.理清概念 并行与并发: *并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。 *并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。 2.线程创建 * 继承thread类创建多线程 public class Example01 { public static void main(String[] args) { MyThread myThread = new MyThread(); //创建线程 MyThread 的线程对象 myThread.start(); //开启线程 while(true){ System.out.println("main 方法在运行"); } } } class MyThread extends Thread{ public void run(){ while (true){ System.out.println("MyThread 类的 run()方法在运行"); } } } * 实现Runnable接口创建线程 public class Example01 { public static void main(String[] args) { MyThread myThread = new MyThread(); //创建线程 MyThread 的线程对象 Thread thread = new Thread(myThread); //创建线程对象 thread.start(); //开启线程,执行线程中的run()方法 while(true){ System.out.println("main 方法在运行"); } } } class MyThread implements Runnable{ public void run(){ while (true){ System.out.println("MyThread 类的 run()方法在运行"); } } } * 两种实现多线程方式的对比分析,实现Runnable接口相对于继承Thread类有如下显著的好处 1.可以避免由于java的单继承带来的局限。java不支持多继承(子类不能有多个父类),其他类的子类不能用继承Thread类的方式,只能采用实现Runnable接口的方式 2.适合多个相同程序代码的线程去处理同一个资源的情况,把线程同程序代码、数据有效的分离 * 后台进程 --如果某个线程对象在启动之前调用了setDaemon(true)语句,这个线程就变成一个后台进程 --当前台线程结束后,JVM会通知后台线程 --进程中只有后台线程运行时,进程会结束 3.线程的调度 * 线程的优先级 --static int MAX_PRIORITY 表示线程的最高优先级 相当于值10 --static int MIN_PRIORITY 表示线程的最低优先级 相当于值1 --static int NORM_PRIORITY 表示线程的普通优先级 相当于值5 * 线程休眠 --Thread.sleep() * 线程让步 --Thread.yield() * 线程插队 --join() 4.多线程同步 * 线程安全 --多个线程同时去访问同一个资源时,易引发安全问题。 *同步代码块 class Ticket1 implements Runnable{ private int tickets = 10; //定义变量 赋值 Object lock = new Object(); //定义任意一个对象,用作同步代码块的锁 public void run(){ while (true){ synchronized(lock){ //定义同步代码块 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if(tickets >0){ System.out.println(Thread.currentThread().getName()+"---卖出的票---"+tickets--); }else{ break; } } } } } public class Example01 { public static void main(String[] args) { Ticket1 ticket = new Ticket1(); //创建 Ticket1 对象 //创建并开启四个线程 new Thread(ticket,"线程1").start(); new Thread(ticket,"线程2").start(); new Thread(ticket,"线程3").start(); new Thread(ticket,"线程4").start(); } } *同步方法 class Ticket1 implements Runnable{ private int tickets = 10; //定义变量 赋值 public void run(){ while (true){ saleTicket(); if(tickets <=0){ break; } } } //定义一个同步方法saleTicket() private synchronized void saleTicket(){ if(tickets > 0){ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"---卖出的票---"+tickets--); } } } public class Example01 { public static void main(String[] args) { Ticket1 ticket = new Ticket1(); //创建 Ticket1 对象 //创建并开启四个线程 new Thread(ticket,"线程1").start(); new Thread(ticket,"线程2").start(); new Thread(ticket,"线程3").start(); new Thread(ticket,"线程4").start(); } } *锁死问题 5.多线程通信 *问题引入:假设有两个线程同时去操作同一个存储空间,其中一个线程负责向存储空间中存入数据,另一个线程负责取出数据。 --数据存储类 public class Storage { //数据存储数组 private int[] cells = new int[10]; //inPos 表示存入时数组下标,outPos表示取出时数组下标 private int inPos,outPos; //定义一个put()方法向数组中存入数据 public void put(int num){ cells[inPos] = num; System.out.println("在cells["+inPos+"]中放入数据--"+cells[inPos]); inPos++; if(inPos == cells.length) inPos = 0; //当inPos为数组长度时 将其置为0 } //定义一个get()方法从数组中取出数据 public void get(){ int data = http://www.mamicode.com/cells[outPos];"在cells["+outPos+"]中取出数据--"+data); outPos++; if(outPos == cells.length) outPos = 0; //当outPos为数组长度时 将其置为0 } } --数据存取类 public class Input implements Runnable { private Storage st; private int num; Input (Storage st){ //通过构造方法接收一个Storage对象 this.st= st; } @Override public void run() { while(true){ st.put(num++); //将num存入数组,每次存入后num自增 } } } public class Output implements Runnable { private Storage st; Output(Storage st){ //通过构造方法接收一个Storage对象 this.st = st; } @Override public void run() { while(true){ st.get(); } } } --创建线程 public class ExampleTest02 { public static void main(String[] args) { Storage st = new Storage(); //创建数据存储对象 Input input = new Input(st); //创建Input对象传入Storage对象 Output output=new Output(st); //创建Output对象传入Storage对象 new Thread(input).start(); //开启新线程 new Thread(output).start(); //开启新线程 } } * 问题解决:测试发现上述存取进程是随机的,未按照顺序轮流执行。如需按照一定顺序轮流执行,此时需要让进程间进行通信 --在Object类中提供了wait(),notify(),notifyAll()方法用于解决线程间的通信问题,因为Java中的所有类都是Object类的子类或间接子类,因此任何类的实例对象都可以直接使用这些方法。 --void wait() 使当前线程放弃同步锁并进入等待,直到其他线程进入此同步锁,并调用notify()或notifyAll()方法唤醒该线程为止 --void notify() 唤醒此同步锁上等待的第一个调用wait()方法的线程 --void notifyAll() 唤醒此同步锁上调用wait()方法的所有线程 public class Storage { private int[] cells = new int[10]; //数据存储数组 private int inPos,outPos; //inPos 表示存入时数组下标,outPos表示取出时数组下标 private int count; //存入或取出数据的数量 //定义一个put()方法向数组中存入数据 public synchronized void put(int num){ //存入数据如果等于cells的长度,此线程等待 while(count == cells.length){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } cells[inPos] = num; System.out.println("在cells["+inPos+"]中放入数据--"+cells[inPos]); inPos++; if(inPos == cells.length) inPos = 0; //当inPos为数组长度时 将其置为0 count++; this.notify(); } //定义一个get()方法从数组中取出数据 public synchronized void get(){ while(count == 0){ //如果count为0 此线程等待 try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } int data = http://www.mamicode.com/cells[outPos];"在cells["+outPos+"]中取出数据:"+data); cells[outPos] = 0; outPos++; if(outPos == cells.length) outPos = 0; //当outPos为数组长度时 将其置为0 count--; this.notify(); } } 注意:如果wait(),notify(),notifyAll()方法调用者不是同步锁对象,JVM会抛出 java.lang.IllegalMonitorStateException
j2ee(5) 线程
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。