zoukankan      html  css  js  c++  java
  • 多线程

    进程:正在运行的程序

    线程:进程中的执行单元,负责执行当前进程的执行,进程包括至少一个线程

    程序运行后有至少一个进程,一个进程可以有多个线程

    多线程:一个程序中有多个线程在同时执行

    程序运行原理:分时调度(cpu平均分配时间);抢占式调度(让优先级高的线程先使用cpu,优先级相同的话,cpu随机分配时间)

    java程序使用抢占式调度的方式

    多线程程序不能调程序的运行速度,但可以提高程序的运行效率,提高cpu的使用率

    主线程:main方法

    //main的主线程
            //程序从上到下执行的过程
            //Demo02在编译运行时,会启动jvm,运行Demo02,Main,找os开线程
            //对于cpu就有一个执行路径,运行Main方法,路径有个名字叫"main"
            //System.out.println(0/0);
            for(int i =0;i<1000000;i++){
                System.out.println(i);
            }
            System.out.println("这是最后一句话");

    thread类

    不能直接用thread类创建对象,应为此类中的run()方法里面没有内容,调用方法没有意义

    构建线程的两种方式:1、继承thread类,并重写run()方法 2、实现runnable接口,并重写run()方法,把此对象放入thread构造方法中

    继承thread类:

    public class MyThread extends Thread {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            for(int i=0;i<100;i++){
                System.out.println("新建"+i);
            }
        }
    }

    方法:start()方法,开启线程;

    sleep()方法,静态方法,让当前的线程休眠;

    currentthread()方法,静态方法获得当前运行的线程对象;

    getname()方法,获得线程名称

    MyThread my = new MyThread();
            //my.start();
            System.out.println(my.getName());
            Thread m = Thread.currentThread();
            System.out.println(m.getName());
            }

    有参构造的子类

    public class MyThread extends Thread {
        MyThread(String name){
            super(name);
        }
        @Override
        public void run() {
            
        }
    }

    继承thread类,其所有的方法也被子类继承过来,静态方法用子类直接调用,也可以在子类的run方法里使用

    实现runnable接口:

     创建一个runnable接口的实现类,把这个实现类的对象放到thread的构造函数中,创建线程

    public class RunThread implements Runnable {
        public void run() {
            // TODO Auto-generated method stub
            for(int i =0;i<50;i++){
                System.out.println("runnable"+i);
            }
        }
    }
    Thread t = new Thread(new RunThread());
            t.start();

    一般都是用runnable接口的方式来创建线程,它的好处在于:

    更加符合面向对象的思想,线程分为线程对象(thread对象)和线程任务(run方法),继承thread类的方法,创建子类对象,对象和任务耦合在一起(违反了低耦合高内聚的规则),使用runnable接口,把线程任务单独封装成对象,类型为runnable接口类型,实现了对线程对象和线程方法的解耦

    匿名内部类在线程中的使用:

    new Thread(){
                public void run(){
                    for(int i =0;i<5;i++){
                        System.out.println("thread"+i);
                    }
                }
            }.run();
            new Thread(new Runnable() {
                public void run() {
                    for(int i =0;i<5;i++){
                        System.out.println("runnable"+i);
                    }
                }
            }).start();

    匿名内部类:快速创建子类的并调用方法的一种快捷方式

    线程池:容纳多个线程的容器,里面的线程可以反复使用

    线程池工厂--------线程池--------线程

    executors-------executorservice--------thread

    方法:submit()提交线程,可以返回一个future<>类型的返回值;shutdown()关闭线程池

    ExecutorService ex =  Executors.newFixedThreadPool(5);
            ex.submit(new MyRunnable());
            ex.submit(new MyRunnable());
            ex.shutdown();
    ExecutorService es = Executors.newFixedThreadPool(3);
            Future<String> f = es.submit(new MyCallable());
            String s = f.get();
            System.out.println(s);

     多线程

    线程安全:由全局变量和静态变量引起的,只是读的话不会有线程安全问题,但是有写操作的话,就涉及到线程安全问题 

    线程同步:解决线程安全问题

    1、同步代码块   synchronized

    2、同步方法   synchronized

    3、使用lock接口

    同步代码块

    synchronized(锁对象),对象可以是任意对象,但是多线程中,必须保证是多个线程共同操作的对象

    public class Tickets implements Runnable {
        private int ticket =1;
        //private Object obj = new Object();
        @Override
        //每个线程在遇到同步代码块的时候,线程会先判断同步锁有没有,如果有,就获取同步锁,进入同步区执行代码
        //执行完毕后,把锁还回去
        //在同步中,线程进行了休眠,此时,另一个线程会执行,遇到同步代码块的时候,会判断有没有同步锁,没有的话,
        //此线程不会同步执行,被阻挡在同步代码块外面
        public void run() {
            // TODO Auto-generated method stub
            while(true){
                synchronized (this) {
                    if(ticket<101){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"出售第"+ticket++);
                    }    
                }
            }
        }
    
    }

    同步方法:对线程内要执行的操作,用一个方法封装,方法用synchronized修饰,把这个方法,放到run方法里

    public class Tickets implements Runnable {
        private int ticket =1;
        private Object obj = new Object();
        public void run() {
            // TODO Auto-generated method stub
            while(true){
                    method();
            }
        }
        //同步方法
        //问题1:同步方法有锁吗?有,锁是本类引用this
        //问题2:同步方法是静态的,还有同步锁吗?是this吗?不是,是本类自己tickets.class
        public synchronized void method(){
            if(ticket<101){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"出售第"+ticket++);
            }
        }
    }

     lock接口:使用reentrantlock实现类来创建lock对象,使用里面的方法,来实现同步的功能

    lock(),获取锁       unlock(),释放锁

    public class Tickets implements Runnable {
        private int ticket =1;
        private Lock lock = new ReentrantLock();
        public void run() {
            while(true){
                lock.lock();
                    if(ticket<101){
                        try {
                            Thread.sleep(100);
                            System.out.println(Thread.currentThread().getName()+"出售第"+ticket++);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }finally{
                            lock.unlock();
                        }
                        
                    }    
            }
        }
    
    }

     注意:一般同步中不要再嵌套同步,否则容易产生程序无限等待的情况,也就是死锁现象

    等待唤醒机制:通过一定的手段使各个线程能有效的利用资源,必须有同步才能使用,因为要用锁对象调用方法,唤醒或者等待这个锁的线程

    线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同

    wait()方法:冻结此线程

    notify()方法:释放被wait()冻结的线程,一次只能一个,而且是任意的

    notifyall()方法:释放所有被wait()的线程

     注意:最好对共有元素创建的类,加一个标价的成员变量

    public class Resource {
        public String name;
        public String sex;
        public boolean flag=false;
    }
    public class Input implements Runnable {
        private Resource r;
        int i =0;
        public Input(Resource r){
            this.r= r;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(true){
                synchronized (r) {
                    if(r.flag){
                    if(i%2==0){
                        r.name="张三";
                        r.sex = "男";
                    }else{
                        r.name = "lisi";
                        r.sex = "nv";
                    }
                    i++;
                    r.flag= false;
                    r.notify();
                    }else{
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    }
                }
            }
        }
    
    }
    public class Output implements Runnable {
        private Resource r;
        public Output(Resource r){
            this.r= r;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                synchronized (r) {
                    if(!r.flag){
                    System.out.println(r.name + "..." + r.sex);
                    r.flag=true;
                    r.notify();
                    }else{
                      
                        try {
                            r.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        }
                    
                }
            }
        }
    
    }
    Resource r = new Resource();
            Input in = new Input(r);
            Output out = new Output(r);
            Thread t1 = new Thread(in);
            Thread t2 = new Thread(out);
            t1.start();
            t2.start();

    构造方法的灵活使用,可以传参

  • 相关阅读:
    .Net基础:CLR基本原理
    行业软件开发商怎样来抢 BI 这块蛋糕?
    免费报表工具知多少?
    哪款报表工具更适合行业软件开发商?
    报表如何通过参数控制数据权限
    实现报表滚动到底部翻页效果
    报表 BI 选型的那些事
    零编码制作报表可能吗?
    为什么说当前报表开发的工作量主要在数据源环节?又如何解决呢?
    用存储过程和 JAVA 写报表数据源有什么弊端?
  • 原文地址:https://www.cnblogs.com/yelena-niu/p/9239091.html
Copyright © 2011-2022 走看看