Java笔记day10

一,不同方式创建多个线程并打印

(1)定义了一个RunA实现Runnable接口,定义list存储数据,并重写了run方法 ,在run方法里定义循环向list中添加数据a;在main方法中创建a,b两个线程并引用该run方法,输出run对象的list和长度

 public static void mainB(String[] args) {
        RunA run=new RunA();
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(run.list);
        System.out.println(run.list.size());
    }
}
class RunA implements Runnable{
    public List list=new ArrayList();
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            list.add("a");
        }
    }
}

 

(2) 创建一个ThreadA类继承Thread(线程)定义一个list来存储数据,重写run方法,在main方法中创建ThreadA的对象线程a,b,并启动线程

class ThreadA extends Thread{
    public List list=new ArrayList();
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            list.add("a");
        }
    }
}
 //2.
    public static void mainB(String[] args) {
        RunA run=new RunA();
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(run.list);
        System.out.println(run.list.size());
    }
}

二,锁对象  Lock

注意:用Lock需要加锁解锁

创建锁对象

Lock lock=new ReentrantLock();//创建锁对象
//Lock lock=new ReentrantLock(true);//加true  设置为公平锁

加锁   成功返回true   失败返回false

lock.lock();

 解锁

lock.unlock();

 创建method方法,在主方法中调用,创建a,b线程并运行

package com.easy725;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class EasyThreadB {

    //锁对象  Lock
    //用lock需要加锁解锁
    Lock lock=new ReentrantLock();//创建锁对象
    //Lock lock=new ReentrantLock(true);//加true  设置为公平锁
    //锁默认非公平锁
    public void method(){
//        lock.lock();//加锁
        //lock.tryLock()//尝试加锁   加锁成功true   失败返回false
        if(lock.tryLock()){//尝试加锁

        System.out.println(Thread.currentThread().getName()+"进入方法");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"结束方法");
        lock.unlock();//解锁
        }else{
            System.out.println("未成功加锁======去执行其它代码");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            method();
        }
    }

    public static void main(String[] args) {
        Runnable run=new EasyThreadB()::method;//当调用runnable里面的run方法时,相当于调用method方法·
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
    }
}

在运行过程中一次只能给加一个锁,下一个使用需要等待该锁解锁才能使用。进程0加锁成功先进入方法,执行进程;同时进程1请求加锁, 进入等待状态;直到进程0结束,同时还没有解锁,所以还会发生一次未成功加锁,然后发生解锁,进程1加锁成功进入方法

 

 三,读锁和写锁

进程进入方法后,写锁可以多个同时访问,读锁只能一个访问结束后才能开始下一个,读锁和写锁不能同时访问,只能写锁或读锁结束才能开始读锁或写锁。

main线程的任务是启动这些线程

cpu分配资源时是随机的,main线程在启动完别的线程以后它的结束也是随机的

所有锁都默认为非公平锁,只有ReentranLock可以设置为公平锁

package com.easy725;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class EasyThreadC {
    public static ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();
    public static ReentrantLock rl=new ReentrantLock();

    public static void method(){
        System.out.println(Thread.currentThread().getName()+"进入方法");
        Lock lock= rrwl.readLock();//读锁
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"加锁成功---读锁");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"方法结束");
        lock.unlock();
    }

    public static void methodWrite(){
        System.out.println(Thread.currentThread().getName()+"进入方法");
        Lock lock= rrwl.writeLock();//写锁
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"加锁成功---写锁");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"方法结束");
        lock.unlock();
    }


    public static void main(String[] args) {
        Runnable run=EasyThreadC::method;
        Runnable runWrite=EasyThreadC::methodWrite;
        Thread a=new Thread(run);
        a.start();
        Thread b=new Thread(run);
        b.start();
        Thread c=new Thread(run);
        c.start();
        Thread d=new Thread(run);
        d.start();
        Thread e=new Thread(run);
        e.start();

        Thread f=new Thread(runWrite);
        f.start();
        Thread g=new Thread(runWrite);
        g.start();
        Thread h=new Thread(runWrite);
        h.start();
        Thread i=new Thread(runWrite);
        i.start();
        System.out.println("main线程结束----");
    }
}

 四,wait  和  notify  (等待和唤醒)

wait()方法可以使线程进入等待状态(在等待池等待)(只有锁对象才能调用wait方法)

OBJ.wait();//让执行到该行代码的线程进入等待状态(在等待池等待)(只有锁对象才能调用wait方法)

锁对象:synchronized关键字或显示锁ReentrantLock

例:

synchronized (OBJ){}//这里OBJ就是锁对象

notify()唤醒一条被该锁对象wait的线程   非公平锁

notifyAll();唤醒全部被锁对象wait的线程

synchronized (OBJ){
    OBJ.notify();//唤醒一条被该锁对象wait的线程   非公平锁
    OBJ.notifyAll();//唤醒全部被锁对象wait的线程     

wait和sleep的区别

(1)wait使Object中定义的方法 ,可以有锁对象,让执行到改行代码的线程进入到等待状态

sleep使Thread类中定义的静态方法,可以让执行到改行的线程进入等待状态

(2)区别:1.sleep需要传入一个毫秒,到达时间会自动唤醒

wait不能自动唤醒,必须要调用notify或notifyAll方法唤醒

2.sleep方法保持锁状态进入等待状态   

wait方法会解除锁状态,其他线程可以进入运行

package com.easy725;

public class EasyThreadD {
    public static final Object OBJ=new Object();//常量全部大写

    public static void method(){
        System.out.println(Thread.currentThread().getName()+"进入方法");

        synchronized (OBJ){
            OBJ.notify();//唤醒一条被该锁对象wait的线程   非公平锁
//            OBJ.notifyAll();//唤醒全部被锁对象wait的线程
            System.out.println(Thread.currentThread().getName()+"进入同步代码块");
            try {
                try {
                    System.out.println(Thread.currentThread().getName()+"进入等待状态");
                    OBJ.wait();//让执行到该行代码的线程进入等待状态(在等待池等待)(只有锁对象才能调用wait方法)
                    System.out.println(Thread.currentThread().getName()+"重新运行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"结束同步代码块");
            OBJ.notify();//必须在同步代码块中才能唤醒
        }
    }

    public static void main(String[] args) {
        Runnable run=EasyThreadD::method;
        Thread a=new Thread(run);
        a.start();
        Thread b=new Thread(run);
        b.start();
        Thread c=new Thread(run);
        c.start();
        Thread d=new Thread(run);
        d.start();
    }

}

五,线程池   池==重用

功能:完成线程的创建和管理,销毁线程

(1)使用ThreadPoolExecutor创建一个线程池tpe

BlockingQueue qu=new ArrayBlockingQueue(12);
ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,10,10,
        TimeUnit.SECONDS,qu,Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

(2)线程任务   Runnable   Callable

Runnable通过execute方法提交到线程池执行

Callable通过submit犯法提交到线程池执行,并返回一个futur对象,用来获取任务结果,使用Future.get()方法获取结果,这样可以阻塞主线程直到仍无执行完成

创建一个工作队列qu用来存放待执行的任务,( 创建Runnable任务run并提交到线程池执行)创建callable任务call到线程池执行,并获取future对象

注意:线程池对象需要关闭,使用shutdouwn()销毁线程

package com.easy725;

import java.util.Queue;
import java.util.concurrent.*;

public class EasyExecuters {
    //线程池   池==重用
    //完成线程创建和管理,销毁线程
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        BlockingQueue qu=new ArrayBlockingQueue(12);
        ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,10,10,
                TimeUnit.SECONDS,qu,Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

        //线程任务  Runnable   Callable
        Runnable run=EasyExecuters::method;
        tpe.execute(run);

        Callable<String> call=EasyExecuters::methodCall;
        Future<String> f=tpe.submit(call);
//        tpe.submit(run);

        System.out.println(f.get());//会等待线程执行完毕

        //线程池对象需要关闭
        tpe.shutdown();//销毁线程,关闭
    }
    public static void method(){
        System.out.println(Thread.currentThread().getName()+"执行代码");
    }
    public static String methodCall() throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"执行代码call");
        Thread.sleep(2000);
        return "callResult";
    }
}

 六  线程池

1,线程池的七个参数

BlockingQueue queue=new ArrayBlockingQueue(12);
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(
        5,8,10,
        TimeUnit.SECONDS,queue, Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()
);//(核心线程数,最大线程数,空闲线程存活时间,空闲线程存活时间单位,工作队列,线程工厂,拒绝策略)

2.四中回绝策略

AbortPolicy 放弃该任务并会抛出一个异常.RejectedExecutionException

CallerRunsPolicy 调用者执行,让传递任务的线程执行此任务

DiscardOldestPolicy 放弃队列中时间最长的任务,不会抛出异常

DiscardPolicy 直接放弃新的任务,不会抛出异常

3.线程池的工作原理

任务放置在工作队列中

1)池中是否有空闲的线程,如果有让该线程执行任务

2)如果池中有空闲的 线程,判断池中的线程数量没有达到核心线程数

3)如果没有达到核心线程数,创建新的线程执行任务,直到填满核心线程数,如果已经达到, 优先在队列中存储线程,直到队列填满

4)工作队列填满后再添加新的任务,判断是否达到最大线程数,如果没有就创建新的线程执行任务 ,直到创建到最大线程数

5)已经填满最大线程数,队列也已经填满,没有空闲的线程吗,就执行回绝策略 ;线程池中的线程达到(超过)核心线程数,超出的数量会根据存活时间进行销毁,直到数量达到核心线程数 。如果线程的数量少于核心线程数,不会消亡

4.java中内置的线程池对象

1)Executors.newCachedThreadPool();可以根据工作任务来创建线程,如果没有空闲的线程就创建新的线程,线程存活时间使60s

2)Executors.newFixedThreadPool(10);设定最大线程数量

3)Executors.newScheduledThreadPool(10);提供定时运行的处理方案

4)Executors.newSingleThreadExecutor();创建一个具有单个线程的线程池,保障任务队列完全按照顺序执行

理论上可以无线创建线程数

ExecutorService threadPoolExecutor=Executors.newCachedThreadPool();

package com.easy725;

import java.util.concurrent.*;

public class EasyExcutersA {
    public static void main(String[] args) {

    BlockingQueue queue=new ArrayBlockingQueue(12);
    ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(
            5,8,10,
            TimeUnit.SECONDS,queue, Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()
    );
//    ExecutorService threadPoolExecutor=Executors.newCachedThreadPool();//理论上线程数是无限创建的
    Runnable run=()->{
        System.out.println(Thread.currentThread().getName()+"执行代码");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"执行完毕");
    };
    for(int i=0;i<17;i++){
        threadPoolExecutor.execute(run);
    }
    threadPoolExecutor.shutdown();
    }
}

 

执行线程为17个,核心线程数刚好满五个

  • 24
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值