代码改变世界

多线程

2018-06-28 15:55  yelena  阅读(119)  评论(0编辑  收藏  举报

进程:正在运行的程序

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

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

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

程序运行原理:分时调度(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();

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