Java多线程学习笔记

多线程

1.Process和Thread

  • 程序 是指指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念
  • 进程 则是执行程序的一次执行过程,他是一个动态的概念,是系统资源分配的单位
  • 通常在一个进程中可以包含若干个线程,一个进程中至少有一个线程,不然没有存在的意义,线程是CPU调度和执行的单位
  • 注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器,如果是模拟出来的多线程,即在一个cpu 的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉

2.多线程的三种创建方法

(1)继承 Thread 类(重点)

//创建线程方法一步骤:继承Thread类,重写run()方法,调用start开启线程
//总结:注意,线程开启不一定立即执行,由cpu调度执行
public class TestThread02 extends Thread{
    @Override
    public void run() {
    	//run方法线程体
        for (int i = 0; i < 100; i++) {
            System.out.println("学习线程--"+i);
        }
    }
    public static void main(String[] args) {
    	//main线程,主线程
    	//创建一个线程对象
        TestThread02 testThread = new TestThread02();
        testThread.start();//开启线程
        for (int i = 0; i < 1000; i++) {
            System.out.println("努力学习多线程--"+i);
        }
    }
}

(2)实现 Runnable 接口(重点)

//创建线程方法二步骤:实现runnable接口,重写run方法,
//执行线程需要丢入runnable接口实现类,调用start方法
public class TestThread01 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("学习多线程体---" + i);
        }
    }
    public static void main(String[] args) throws InterruptedException {
    	//创建runnable接口的实现类对象
        TestThread01 testThread01 = new TestThread01();
        //创建线程对象,通过线程对象来开启我们的线程,代理
        Thread thread = new Thread(testThread01);
        thread.start();
//        new Thread(new TestThread01()).start();
        for (int i = 0; i < 100; i++) {
            if(i%10==0) thread.sleep(20);
            System.out.println("我在学习多线程--"+i);
        }
    }
}

(3)实现 Callable 接口(了解)

  • 实现Callable接口,需要返回值类型
  • 重写call方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
  • 提交执行:Future result1 = ser.submit(t1);
  • 获取结果:boolean r1 = result1.get();
  • 关闭服务:ser.shutdownNow();

3.静态代理

//静态代理模式总结:
//真实对象和代理对象都要实现同一个接口
//代理对象要代理真实角色

//好处:代理对象可以做很多真实对象做不了的事情
//真实对象专注做自己的事情
public class StaticProxy {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我爱你");
            }
        }).start();
        new WeddingCompany(new You()).HappyMarry();
//        You you = new You();//你要结婚
//        WeddingCompany weddingCompany = new WeddingCompany(you);
//        weddingCompany.HappyMarry();
    }
}
//接口
interface Marry{
    void HappyMarry();
}
//真实结婚角色
class You implements Marry{
    //重写方法
    @Override
    public void HappyMarry() {
        System.out.println("小红要结婚了");
    }
}
//代理角色,帮助结婚
class WeddingCompany implements Marry{
    private Marry target;//代理对象
    public WeddingCompany(Marry target) {
        this.target = target;//代理谁——》真实目标对象
    }
    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();//真实对象
        after();
    }
    private void after() {
        System.out.println("结婚之后,收尾款");
    }
    private void before() {
        System.out.println("结婚之前,布置现场");
    }
}

4.Lambda表达式

函数式接口的定义:任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口。

/*
总结:
    lambda表达式只能有一行代码的情况下才能简化为一行,如果有多行,那么就用代码块包裹
    前提是接口为函数式接口
    多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
    interface ILove{
    void love(int a,int b,int c);
    public static void main(String[] args){
        ILove love = null;
        love = (a,b,c)->{
            System,out.println("i love you" + a+b+c);
            System.out.println("i love you too");
        }
        love.love(520,13,14);
    }
 */
public class TestLambda01 {

    //3.静态内部类
    static class Like1 implements ILike{
        @Override//重写方法
        public void lambda() {
            System.out.println("i like lambda02");
        }
    }
    //主函数
    public static void main(String[] args) {
        //4.局部内部类
        class Like2 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda03");
            }
        }
        ILike like = new Like();
        like.lambda();//类
        like = new Like1();
        like.lambda();//静态
        like = new Like2();
        like.lambda();//局部
        //5.匿名内部类,没有类的名称,必须借助接口或者父类
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("i like lambda04");
            }
        };
        like.lambda();//匿名
        //6.用lambda简化
        like = ()->{
            System.out.println("i like lambda05");
        };
        like.lambda();//简化
    }
}
//1.定义一个函数式接口
interface ILike{
    void lambda();
}
//2.实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("i like lambda01");
    }
}

5.停止线程

//测试stop方法,
//建议线程正常停止,利用次数,不建议死循环
//建议使用标志位,不要使用stop或者destroy等过时或者JDK不建议使用的方法
public class TestStop implements Runnable{
	private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while(flag){
        	System.out.println("run....Thread"+i++);
        }
    }
    public void stop(){
		this.flag = false;
	}
    public static void main(String[] args) throws InterruptedException {
        //启动线程
        TestStop testStop = new TestStop();
        Thread thread = new Thread(testStop);
        thread.start();
        //主线程
        for (int i = 0; i < 500; i++) {
            if(i==200){
                testStop.stop();
                System.out.println("线程该停止了");
            }
        }
    }
}

6.线程休眠

sleep时间达到后线程进入就绪状态,可模拟网络延迟,倒计时
每个对象都有一个锁,sleep不会释放锁

//模拟倒计时...
public class TestSleep01 {

    public static void main(String[] args)  {
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //打印当前系统时间
        Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间
        while (true){
            try {
                Thread.sleep(1000);//每次输出间隔1s
//                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
//                String dateString = simpleDateFormat.format(startTime);
//                System.out.println(dateString);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                startTime = new Date(System.currentTimeMillis());//更新时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void tenDown() throws InterruptedException {
        int num = 10;
        while(true){
            Thread.sleep(1000);
            System.out.println(num--);
            if(num<=0) break;
        }
    }
}
//模拟网络延迟:放大问题的发生性
public class TestSleep02 implements Runnable{
    private int ticketNum = 10;
    @Override
    public void run() {
        while (true){
            if(ticketNum<=0) break;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNum--+"票");
        }
    }
    public static void main(String[] args) {
        TestSleep02 ticket = new TestSleep02();
        new Thread(ticket,"小明").start();
        new Thread(ticket,"抢票的人").start();
        new Thread(ticket,"黄牛").start();
    }
}

7.线程礼让 Yield

//测试礼让线程,让当前执行的线程暂停,但不阻塞
//礼让不一定成功,看cpu心情
public class TestYield {

    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
    }
}
class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();//礼让
        System.out.println(Thread.currentThread().getName()+"线程停止执行");
    }
}

8.Join合并线程

//测试join方法,想象为插队:待此线程执行完成后,再执行其他线程,其他线程阻塞
public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("vip线程来了"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //启动线程
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();
        //主线程
        for (int i = 0; i < 500; i++) {
            if(i==200){
                thread.join();//插队
            }
            System.out.println("main"+i);
        }
    }
}

9.线程优先级

线程的优先级用数字表示1~10,表示概率,还是要看CPU的调度

public class TestPriority {
    public static void main(String[] args) {
        //主线程默认优先级
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
        MyPriority myPriority = new MyPriority();
        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        Thread t5 = new Thread(myPriority);
        Thread t6 = new Thread(myPriority);
        //先设置优先级,再启动
        t1.start();
        t2.setPriority(1);
        t2.start();
        t3.setPriority(4);
        t3.start();
        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();
        t5.setPriority(7);
        t5.start();
        t6.setPriority(2);
        t6.start();
    }
}
class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

10.守护线程 daemon

//测试守护线程
//例子:上帝守护人   
public class TestDaemon {
    public static void main(String[] args) throws InterruptedException {
        God god = new God();
        Person person = new Person();
        Thread t2 = new Thread(person);
        Thread thread = new Thread(god);
        thread.setDaemon(true);//默认为false表示用户线程,正常的线程都是用户线程
        thread.start();//上帝守护线程启动
        new Thread(person).start();//用户线程启动
    }
}
//上帝
class God implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("上帝保佑着你");
        }
    }
}
//人
class Person implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 3600; i++) {
            System.out.println("人开心的活着");
        }
        System.out.println("=====goodBye===========");
    }
}

11.线程状态

//观察测试线程的状态
public class TestState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("//");
        });
        //观察状态
        Thread.State state = thread.getState();
        System.out.println(state);//NEW
        //观察线程后
        thread.start();//启动线程
        state = thread.getState();//节约空间
        System.out.println(state);//Run
        while(state != Thread.State.TERMINATED){//只要线程不终止,就一直输出状态
            Thread.sleep(100);
            state = thread.getState();//更新线程状态
            System.out.println(state);//输出状态
        }
    }
}

12.线程同步

锁机制 synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待使用后释放锁即可
synchronized关键字包括两种方法:
synchronized方法 public synchronized void method(int args){ }
synchronized块 synchronized(Obj){ }

public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();
        new Thread(station,"酷酷的小明").start();
        new Thread(station,"牛牛").start();
        new Thread(station,"可恶的黄牛").start();
    }
}
class BuyTicket implements Runnable{
    private int ticketNum = 10;
    boolean flag = true;//外部停止方法
    @Override
    public void run() {
        //买票
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
        }
    }
    
    private synchronized void buy() throws InterruptedException {
        //判断是否有票
        if(ticketNum<=0){
            flag = false;
            return;
        }
        //模拟延时
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNum--);
    }
}
public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list){//同步块
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        Thread.sleep(3000);
        System.out.println((list.size()));
    }
}

13.使用线程池

JDK5.0起提供了线程池相关API: ExecutorService和Executors(工具类,线程池的工厂类)

public class TestPool {
    public static void main(String[] args) {
        //1.创建服务,创建线程池
        //newFixedThreadPool 参数为:线程池的大小
        ExecutorService service = Executors.newFixedThreadPool(10);
        //执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //关闭连接池
        service.shutdown();
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值