多线程基础-Thread、Runnable、Callable、线程状态等...

多线程基础

了解多线程

不再概述。。。。百度都有

多线程的三种方式

Thread

package com.jiang.thread01;

/**
 * @Title: 继承Thread
 * @author: JiangPeng
 */

//继承thread类,重写run方法,调用start方法进行启动
public class thread01 extends Thread {
    public static void main(String[] args) {
        //创建子类对象
        thread01 t = new thread01();
        t.start(); //调用子类对象的start方法
        for(int i=0;i<10000;i++){
            System.out.println("我在写代码");
        }

    }

    @Override //线程的入口点
    public void run() {
        //线程体
        for(int i=0;i<10000;i++){
            System.out.println("我在听歌");
        }
    }
}
  1. 我们要继承Thread,重写Thread类的run方法。
  2. 这个run()方法就是我们线程的入口点
  3. run方法内部就是我们的线程体,我们在线程体中输出1万次我在听歌
  4. 在主方法下,我们首先要创建子类对象,通过子类对象调用start方法启动线程
  5. 在启动线程后 输出1万次的我的在写代码。
  6. 此时我们可以在控制台看到,我的写代码和我在听歌是一前一后一前一后,不规则排序,这就是因为我们启动多线程之后,两条输出语句是同时被CPU进行处理,但是先后顺序我们是控制不了,只靠CPU随机选择。
  7. 当然如果你把 start方法启动线程放在最后,那么你会看到1万次我在写代码之后再1万次我在听歌。
  8. start是开启线程,会自动调用run方法。run方法只是一个单纯方法。

Runnable(推荐)


package com.jiang.thread01;

/**
 * @Title:
 * @author: JiangPeng
 */

//实现runnable
public class thread02 implements Runnable {

    public static void main(String[] args) {
        //创建实现类对象
        thread02 t = new thread02();
        //创建代理类对象
        Thread thread = new Thread(t);
        thread.start(); //调用代理类对象的start方法

        //-------
        //我们上面的thread02实现类对象,和thread代理类对象都只用了一次
        //所以我们可以通过匿名的方式进行一次性调用
        new Thread(new thread02()).start(); ///都是一样的效果


        for(int i=0;i<10000;i++){
            System.out.println("我在写代码");
        }
    }

    @Override //线程的入口点
    public void run() {
        //线程体
        for(int i=0;i<10000;i++){
            System.out.println("我在听歌");
        }
    }
}
  1. 首先实现Runnable接口。重写run方法,run是线程的入口点,方法内就是线程体
  2. Runnable与Thread不同的是,Runnable需要创建代理类对象
  3. 即先创建实体类对象 thread02 然后创建thread代理类对象。因为runnable无法直接调用start方法
  4. 当然我们上面的thread02实现类对象,和thread代理类对象都只用了一次,所以我们可以通过匿名的方式进行一次性的调用 new Thread(new thread02()).start(); 效果都是一样的
  • 推荐使用实现Runnable,避免单继承局限

  • 也方便共享资源

    package com.jiang.thread01;
    
    /**
     * @Title: Runnable共享资源,模拟12306抢票
     * @author: JiangPeng
     */
    public class Web12306 implements Runnable {
        private int piao = 100;
    
        @Override
        public void run() {
           while (true){
             if(piao<0){
                break;
             }
               System.out.println(Thread.currentThread().getName()+">>"+piao--);
           }
        }
    
        public static void main(String[] args) {
            Web12306 web = new Web12306();
            new Thread(web,"xiaowang").start();
            new Thread(web,"xiaochen").start();
            new Thread(web,"xiaomeng").start();
        }
    }
    
    • currentThread():当前线程
    • 当然在这里会有一系列的问题,涉及后面的并发,目前不做解释。

Callable

  • 设计并发编程内容,以后再写

静态代理

package com.jiang.thread01;

/**
 * @Title: 静态代理
 * @author: JiangPeng
 *
 * 1.真实角色
 * 2.代理角色
 */
public class StaticProxy {
    public static void main(String[] args) {
        new Wedding(new You()).happyMarry();
        //new Thread(线程对象).start();
    }
}

interface Marry{
    void happyMarry();
}
//真实角色
class You implements Marry{

    @Override
    public void happyMarry() {
        System.out.println("Marry Happy");
    }
}

//代理角色
class Wedding implements Marry{
    // 真实角色
    private Marry target;

    public Wedding(Marry target){
        this.target=target;
    }

    @Override
    public void happyMarry() {
        ready();
        this.target.happyMarry();
        after();
    }
    private void ready(){
        System.out.println("---Marry ready---");
    }
    private void after(){
        System.out.println("---Marry after---");
    }

}
  • 接口Marry:里面有happymarry的方法
  • 类You:真实角色,实现Marry接口,重写happymarry方法
  • 类Wedding:代理角色,实现Marry接口,重写happymarry方法
    • 内部有真实角色 target
    • 通过构造函数this.target= target
  • 主方法new Wedding(new You()).happyMarry();=//new Thread(线程对象).start();

Lambda简化

简单,用一次的线程进行简化

package com.jiang.thread01;

/**
 * @Title: Lambda简化
 * @author: JiangPeng
 */

public class LambdaThread {

    public static void main(String[] args) {
        new Thread(()->{
            //线程体
            for(int i=0;i<10000;i++){
                System.out.println("我在听歌");
            }
        }
        ).start();
    }
}

线程状态

img

五个状态

  • 新生状态:new Thread()...一旦创建就进入到新生状态,有自己的工作空间了,与主内存进行交互
  • 就绪状态:start()...进入就绪状态,只能表示具备运行的能力,还没有分配到CPU,处于就绪队列
  • 运行状态:被CPU调度运行
    • sleep:抱着资源,不给别人用。
    • wait:等待,可以给别人用
    • join:插队
    • read write
  • 阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态
    • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
    • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
    • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
  • 死亡状态:执行完毕,或者stop方法

就像大学生毕业>>准备找工作>>上班>>被裁

线程终止

终止线程:

​ 1.线程正常结束--》次数
​ 2.外部干涉 --》加入标识

不要使用stop/destory方法,不安全。

package com.jiang.thread01;

/**
 * @Title:
 * @author: JiangPeng
 */


public class TerminateThread implements Runnable {
    //加入标识,标记线程体是否可以运行。
    private boolean flag = true;
    private String name;

    public TerminateThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        int i = 0;
        //关联标识,true->运行,false->停止。
        while(flag){
            System.out.println(name+"-->"+i++);
        }
    }
    //对外提供方法,改变标识
    public void terminate(){
        this.flag=false;
    }
    public static void main(String[] args) {
        TerminateThread terminateThread = new TerminateThread("jack");
        new Thread(terminateThread).start();

        for (int i=0;i<=99;i++){
            if(i==88){
                terminateThread.terminate();//线程终止
                System.out.println("线程手动终止");
            }
            System.out.println("main->"+i);
        }
    }
}

暂停sleep

package com.jiang.thread01;

/**
 * @Title:
 * @author: JiangPeng
 */
public class BlockedSleep {

    public static void main(String[] args) {
        Web12306 web = new Web12306();
        new Thread(web,"xiaowang").start();
        new Thread(web,"xiaochen").start();
        new Thread(web,"xiaomeng").start();
    }
    static class Web12306 implements Runnable {
    private int piao = 100;

    @Override
    public void run() {
        while (true) {
            if (piao < 0) {
                break;
            }
            try{
                Thread.sleep(200);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ">>" + piao--);
        }
    }
}
}

通过 Thread.sleep(200);使的进程之间暂停200秒后进行下一步的操作
sleep模拟了网络延时,增大了出现问题的可能性

礼让yield

让当前正在执行的线程暂停,不是阻塞线程,而是将线程从运行状态转入就绪状态,让cpu重新调度

package com.jiang.thread01;

/**
 * @Title:
 * @author: JiangPeng
 */
public class Yield {
    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()+">>start");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+">>end");
    }
}

其实就是怕防止某个进程一直使用。比如抢票 不能让某个黄牛一直都能抢得到

插队join

合并线程,插队线程

package com.jiang.thread01;

/**
 * @Title:
 * @author: JiangPeng
 */
public class BlockedJoin {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            for (int i=0;i<100;i++){
                System.out.println("lambda..."+i);
            }
        });
        t.start();

        for (int i=0;i<100;i++){
            if(i==20){
                t.join();//插队,main被阻塞了
            }
            System.out.println("mian..."+i);
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/pengcode/p/12944257.html