Thread的三种创建方式和一些常用的操作

三种创建Thread方式

  • Thread class
  • Runnable 接口
  • callable 接口

run() 和start的区别

  • run只有主线程一条执行路径
  • start多条执行路径,主线程和子线程并行交替执行

继承Thread

使用common.io下载图片

package thread;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

/**
 * @author by whs
 * @date 2020/12/20.
 */
public class TestThread2 extends  Thread {
    private String  url;
    private String  file;

    public TestThread2(String url,String file){
        this.url = url;
        this.file= file;
    }

    @Override
    public void run() {
        WebDownload webDownload = new WebDownload();
        webDownload.download(url,file);
        System.out.println("下载了图片"+file);
    }

    public static void main(String[] args) {
        TestThread2 testThread2 = new TestThread2("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","2.jpg");
        TestThread2 testThread3 = new TestThread2("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","3.jpg");
        TestThread2 testThread4 = new TestThread2("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","4.jpg");

        testThread2.start();
        testThread3.start();
        testThread4.start();

    }
}
class WebDownload{
    public void  download(String url,String file){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(file));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO 异常,download方法出现问题");
        }

    }
}

实现Runnable

package thread;

/**
 * @author by whs
 * @date 2020/12/20.
 */
public class TestRunnable implements Runnable {

    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码" + i);
        }
    }

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        new Thread(threadTest).start();
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程" + i);
        }
    }
}
  • 继承Thread
    • 启动线程:子类对象.start()
    • 不建议使用:避免OOP单继承局限性
  • 实现Runnable接口
    • 实现接口Runnable具有多线程能力
    • 启动线程:传入目标对象+Thread对象.start()。
    • 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用。

实现Callable

package thread;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

/**
 * @author by whs
 * @date 2020/12/20.
 */
public class TestCallable implements Callable<Boolean> {

    private String  url;
    private String  file;

    public TestCallable(String url,String file){
        this.url = url;
        this.file= file;
    }

    public Boolean call() throws Exception {
        WebDownload2 webDownload2 = new WebDownload2();
        webDownload2.download(url,file);
        System.out.println("下载了图片"+file);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable testThread2 = new TestCallable("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","2.jpg");
        TestCallable testThread3 = new TestCallable("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","3.jpg");
        TestCallable testThread4 = new TestCallable("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","4.jpg");
		//创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
		//执行
        Future<Boolean> submit1 = executorService.submit(testThread2);
        Future<Boolean> submit2 = executorService.submit(testThread2);
        Future<Boolean> submit3 = executorService.submit(testThread2);
		//获取结果
        boolean b = submit1.get();
        boolean b1 = submit2.get();
        boolean b2 = submit3.get();
		//关闭线程池
        executorService.shutdown();

    }
}
class WebDownload2{
    public void  download(String url,String file){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(file));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO 异常,download方法出现问题");
        }
    }
}

静态代理

静态代理

package proxy;

/**
 * @author by whs
 * @date 2020/12/20.
 */
public class TestProxy {
    public static void main(String[] args) {
        You you = new You();
        weddingFactory weddingFactory = new weddingFactory(you);
        weddingFactory.HappyMarry();
    }

}
//结婚接口
interface Marry{

    public void HappyMarry();

}
//你结婚实现类
class You implements Marry{
    public void HappyMarry() {
        System.out.println("开心的结婚");
    }
}
//婚庆公司代理类
class weddingFactory implements Marry{
    private Marry marry;

    public weddingFactory(Marry marry){
        this.marry = marry;
    }

    public void HappyMarry() {
        before();
        this.marry.HappyMarry();
        after();
    }

    private void after() {
        System.out.println("收尾款");
    }

    private void before() {
        System.out.println("布置场景");
    }
}

lamda表达式

  • 避免匿名内部类定义过多

  • 可以让你的代码看起开很简洁

  • 去掉一堆没有意义的代码,只留下核心的逻辑

    (params) ->expression[表达式]
    (params) ->statement[语句]
    (params) ->{statements}

  • 函数式接口的定义:

    • 任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口
    • 对于函数式接口,我们可以通过lamda表达式来创建该接口的对象
 package lambda;
    
    import javax.sound.midi.Soundbank;
    
    /**
     * @author by whs
     * @date 2020/12/20.
     */
    public class TestLambda {
        /*静态内部类*/
       static class Like2 implements  ILike{
            public void lambda() {
                System.out.println("i like lambda2");
            }
        }
    
        public static void main(String[] args) {
    
    
        

ILike like = new Like();
        like.lambda();

        like = new Like2();
        like.lambda();
        /*局部内部类*/
        class Like3 implements  ILike{
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }

        like = new Like3();
        like.lambda();
        /*匿名内部类*/
        like = new ILike(){
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };
        like.lambda();

        /*lambda表达式*/
        like = () ->{
            System.out.println("i like lambda5");
        };
        like.lambda();
        }
    }
    //ILike接口
    interface  ILike{
         public  void lambda();
    }
    //Like实现类
    class Like implements  ILike{
        public void lambda() {
            System.out.println("i like lambda");
        }
    }

线程五大状态

  1. new Thread t = new Thread()线程对象一旦创建就到新生状态
  2. 就绪状态 当调用start()方法,线程立即进入就绪状态,但并不意味着立即调度执行
  3. 运行状态 进入运行状态,线程才真正执行线程体的代码块
  4. 阻塞状态 当调用sleep,wait或者同步锁定时,线程进入阻塞状态,就是代码不往下执行,阻塞事件解除后,重新进入就绪状态,等待cpu调度执行
  5. dead 线程中断,一旦进入死亡状态,就不能再次启动了。

每隔一秒打印时间

package thread;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author by whs
 * @date 2020/12/20.
 */
public class TestSleep  {
    public static void main(String[] args) {
        Date date = new Date(System.currentTimeMillis());
        while(true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
                date = new Date(System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

join

  • join 合并线程,待此线程执行完后,在执行其他线程,其他线程阻塞
  • 可以想象为插队

线程优先级

  • setPriority(int XXX) ;设置优先级
  • getPriority(int xxx) ;得到优先级
  • 设置优先级建议在start()调度前
    Thread.MIN_PRIORITY =1;
    Thread.MAX_PRIORITY=10;
    Thread.NORM_PRIORITY=5

线程不安全

银行取钱

package thread;

/**
 * @author by whs
 * @date 2020/12/21.
 */
public class UnsafeBank  {
    public static void main(String[] args) {
        Account account = new Account(100, "基金");
        Thread thread = new Drawing(account, 100, "you");
        Thread thread1 = new Drawing(account, 50, "girlFriend");

        thread.start();
        thread1.start();
    }
}
//账号类
class  Account{
    private  int money;
    private  String name;

    public  Account(int money,String name){
        this.money = money;
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class  Drawing extends Thread{
    private  Account account;
    private  int  drawingMoney;
    private int nowMoney;


    public  Drawing(Account account ,int drawingMoney ,String name){
            super(name);
            this.account = account;
            this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        //取钱
        if((account.getMoney() - drawingMoney)<0){
            System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
            return ;
        }
        //模拟网络延时
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.setMoney(account.getMoney()-drawingMoney);

        nowMoney = nowMoney + drawingMoney;

        System.out.println(account.getName()+ "余额为:"+account.getMoney());

        System.out.println(this.getName()+"手里的钱"+nowMoney);

    }
}

list中添加线程

package thread;

import java.util.ArrayList;
import java.util.List;

/**
 * @author by whs
 * @date 2020/12/21.
 */
public class TestListThread {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(9000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

同步方法

就是synchronized关键字,它包括两种用法,synchronized方法和synchronized块

  • 同步方法 :public synchronized void method(int age){}

synchronized方法控制“对象”的访问,每一个对象对应一把锁,每个synchronized方法都必须获取调用该方法的对象的锁才行,否者进程阻塞,方法一旦执行,就独占锁,知道方法返回才释放锁,后面被阻塞的线程才能获得锁,继续执行。

  • 缺陷: 若将大的方法申明为synchronized将会影响效率

银行取钱(synchronized)

package thread;

/**
 * @author by whs
 * @date 2020/12/21.
 */
public class UnsafeBank  {
    public static void main(String[] args) {
        Account account = new Account(1000, "基金");
      
        Thread thread = new Drawing(account, 100, "you");
        Thread thread1 = new Drawing(account, 50, "girlFriend");

        thread.start();
        thread1.start();
    }
}
//账户类
class  Account{
    private  int money;
    private  String name;

    public  Account(int money,String name){
        this.money = money;
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class  Drawing extends Thread{
    private  Account account;
    private  int  drawingMoney;
    private int nowMoney;


    public  Drawing(Account account ,int drawingMoney ,String name){
            super(name);
            this.account = account;
            this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        synchronized (account){
            //取钱
            if((account.getMoney() - drawingMoney)<0){
                System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
                return;
            }
            //模拟网络延时
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.setMoney(account.getMoney()-drawingMoney);

            nowMoney = nowMoney + drawingMoney;

            System.out.println(account.getName()+ "余额为:"+account.getMoney());

            System.out.println(this.getName()+"手里的钱"+nowMoney);
        }
    }
}

list问题(synchronized)

package thread;

import java.util.ArrayList;
import java.util.List;

/**
 * @author by whs
 * @date 2020/12/21.
 */
public class TestListThread {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //打印线程个数
        System.out.println(list.size());
    }
}

idea快捷键

  • Ctrl+Shift+上下键 上下移动代码

juc版

package thread;

import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author by whs
 * @date 2020/12/21.
 */
public class TestJuc {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

synchronize和Lock的对比

  • Lock是显示锁(手动开启和关闭锁)synchronized是隐式锁,出了作用域自动释放
  • Lock只有代码块锁,synchronized有代码块锁和方法锁
  • 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性
  • 有限使用顺序:
    • Lock > 同步代码块(已经进入方法体,分配了相应的资源) > 同步方法(在方法体外)

线程通信

  • wait() 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁
  • wait(long timeout ) 指定等待的毫秒数
  • notify() 唤醒一个处于等待状态的线程
  • notifyAll() 唤醒同一个对象上所有调用wait()方法的线程,优先级级别高的线程先的调度

注意:均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常ILLegalMonitorStateException

管程法

package thread;

/**
 * @author by whs
 * @date 2020/12/21.
 */
public class TestPip {
    public static void main(String[] args) {
            SynContainer container = new SynContainer();
            new Producter(container).start();
            new Cousumer(container).start();
    }
}
//生产者
class Producter extends  Thread{
    SynContainer synContainer;

    public  Producter(SynContainer synContainer){
        this.synContainer = synContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            synContainer.push(new Chicken(i));
            System.out.println("生产了第"+ i+ "只鸡");
            
        }
    }
}
//消费者
class  Cousumer extends  Thread{
    SynContainer synContainer;

    public  Cousumer(SynContainer synContainer){
        this.synContainer = synContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {

            System.out.println("消费了第"+ synContainer.pop().id+ "只鸡");

        }
    }
}
//产品
class Chicken {
    int id;
    public Chicken(int id){
        this.id = id;
    }
}
//缓冲区
class SynContainer {
    Chicken[] chickens = new Chicken[10];
    int count = 0;

    public synchronized  void push(Chicken chicken){
        //容器满了,就需要等待消费
        if(count ==chickens.length){
            try {
                this.wait();
                System.out.println(chickens.length);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果没满,就需要丢入产品
        chickens[count] = chicken;
        count++;

        //通知消费
        this.notify();
    }


    public synchronized  Chicken pop(){
        if(count == 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果可以消费
        count--;
        Chicken chicken = chickens[count];

        this.notify();
        return  chicken;
    }
}

线程池

package thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author by whs
 * @date 2020/12/21.
 */
public class TestPool {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //执行线程
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        //关闭线程池
        executorService.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、付费专栏及课程。

余额充值