多线程
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();
构造方法的灵活使用,可以传参