Java多线程(详细最全)

**一.

1.程序 进程 线程**

程序:

  • 程序是指令和数据的一个有序集合,其本身没有任何运行的含义,是一个静态的概念。

进程:

  • 进程是程序执行的一个过程,它是一个动态的概念,是系统资源分配的单位。例如:我们的播放器,游戏等等

线程:

  • 线程是CPU调度和执行的单位,例如:我们程序中的main()被称为主线程,为系统的入口,用于执行整个程序。

小结:

  1. 一个进程至少包括一个线程,不然就没有存在的意义。
    在程序运行时,即使没有创建自己的线程,后台仍然还会有很多线程,例如:main()线程,gc线程等等
  2. 在一个进程中,如果开辟了多个线程,那这些线程的运行由调度器安排调度,先后顺序不能认为干预。
  3. 对同一份资源的操作时,会存在资源抢夺的问题,这个时候就要加入并发控制。例如有100张电影票,但是同时有10000个人来抢,如果不加入并发控制,这个时候票的余额就会出现-9900。

2.如何创建一个进程

	 1. 继承Thread类 
	 2. 继承Thread类 
	 3. 重写run()方法 
	 4. 通过< 子类对象.start()>启动这个线程

实例:

package java_demo.多线程;

import org.apache.commons.io.FileUtils;

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

//通过多线程下载网络图片
public class Thread_download extends Thread{
    private String name;
    private String url;

    public Thread_download(String name, String url) {
        this.name = name;
        this.url = url;
    }

    public void run()
    {
        Download download = new Download();
        download.download(url,name);
        System.out.println("已经下载图片到"+name);
    }

    public static void main(String[] args) {
        Thread_download test1 = new Thread_download("test1", "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=24336452,906724543&fm=26&gp=0.jpg");
        Thread_download test2 = new Thread_download("test2", "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3649178992,1821853682&fm=26&gp=0.jpg");
        Thread_download test3 = new Thread_download("test3", "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3401732207,3726302783&fm=26&gp=0.jpg");
        test1.start();
        test2.start();
        test3.start();
    }
}
class Download{
    public void download(String url,String name)
    {
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载器异常!!!");
        }
    }
}
	 1. 实现Runnable接口 
	 2. 实现Runnable接口 
	 3. 定义无参run()方法 
	 4. 通过<传入目标对象+Thread对象.start()>启动这个线程

实例:

package java_demo.多线程;

import org.apache.commons.io.FileUtils;

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

public class Runnable_download implements Runnable{
    private String name;
    private String url;

    public Runnable_download(String name, String url) {
        this.name = name;
        this.url = url;
    }


    @Override
    public void run() {
        Download download = new Download();
        download.download(url,name);
        System.out.println("已经下载图片到"+name);

    }

    public static void main(String[] args) {
        Runnable_download test1 = new Runnable_download("test1", "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=24336452,906724543&fm=26&gp=0.jpg");
        Runnable_download test2 = new Runnable_download("test2", "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3649178992,1821853682&fm=26&gp=0.jpg");
        Runnable_download test3 = new Runnable_download("test3", "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3401732207,3726302783&fm=26&gp=0.jpg");
        new Thread(test1).start();
        new Thread(test2).start();
        new Thread(test3).start();

    }

}
class Downloads{
    public void download(String url,String name)
    {
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载器异常!!!");
        }
    }
}

小结

  • 建议使用Runnable接口,因为其避免了单继承的局限性,灵活方便,方便一个对象被多个线程使用。

3.lambda表达式

优点

  1. 避免内部匿名类定义过多。
  2. 去掉了一些没有意义的代码,只留下了核心逻辑。

语法格式

  • 语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符 ,读作(goes to)。

4.静态代理模式

总结

  1. 真实的角色 代理角色(需要真实角色的引用)
  2. 共同实现一个接口

实例

package java_demo.多线程;
//静态代理模式
/*
1.真实的角色
2.代理角色
3.共同实现的接口
 */
public class Thread_proxy {
    public static void main(String[] args) {
        Weeding weeding = new Weeding(new You());
        weeding.Happymarry();
    }
}
interface Marry
{
    void Happymarry();
}

class You implements Marry
{

    @Override
    public void Happymarry() {
        System.out.println("我要结婚了,超级开心!!!");
    }
}

class Weeding implements Marry
{
    private Marry marry;

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

    @Override
    public void Happymarry() {
        before();
        this.marry.Happymarry();
        after();
    }
    public void before()
    {
        System.out.println("结婚之前布置现场!!");
    }
    public void after()
    {
        System.out.println("结婚之后数钱!!!");
    }

}

5.线程的生命周期

  • 初始状态:线程对象一旦创建,就进入了初始状态。
  • 就绪状态:当调用start()方法时,线程就进入了就绪状态,但不代表立即调度执行想,需要CPU对你进行调度你才是运行状态,否则一直就是就绪状态。
  • 运行状态:被调度程序选择作为当前线程时的状态。
  • 阻塞状态:当调用sleep,wait或者同步锁时,线程进入阻塞状态,程序不往下继续执行,阻塞事件解除以后,线程重新进入就绪状态,等待调度程序调度。
  • 死亡状态:线程中断或者结束。一旦进入死亡状态,就不能再次启动。

6.线程的停止

  1. 建议使用正常停止——————>利用次数
  2. 建议使用标志位
  3. 不建议使用stop,destroy等jdk不建议使用的过时方法

实例

package java_demo.多线程;


/*
线程停止
1.建议线程正常停止——————>利用次数
2.建议使用标志位
3.不建议使用stop或destroy等过时且jdk不建议使用的方法
 */
public class Thread_stop implements Runnable{
    private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while (flag)
        {
            System.out.println("runTread"+i++);
        }
    }
    public void stop()
    {
        this.flag = false;
    }

    public static void main(String[] args) {
        Thread_stop thread_stop = new Thread_stop();
        new Thread(thread_stop).start();
        for (int i = 0; i < 200; i++) {
            System.out.println("mainThread"+i);
            if (i==100)
            {
                thread_stop.stop();
                System.out.println("run线程已经停止!!!");
            }
        }
    }
}

7.线程休眠

  • 利用sleep方法让线程休眠,进入阻塞状态

实例

package java_demo.多线程;


/*
模拟倒计时
 */
public class Thread_sleep {
    public static void main(String[] args) {
        sleep();
    }
    public static void sleep()
    {
        int num = 10;
        while (true)
        {
            System.out.println("倒计时:"+num--);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (num<=0)
            {
                break;
            }
        }
    }
}

8.线程礼让

  1. 利用yield()方法 让当前线程暂停,但是不进入阻塞状态
  2. 让线程重新回到就绪状态,等待调度程序对其进行调度
  3. 最终CPU调度全靠心情,所以礼让不一定成功。

实例:

package java_demo.多线程;

public class Thread_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()+"线程开始执行!!");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程结束执行!!");
    }
}

9.线程强制执行(插队)
join合并线程,待此线程结束以后再执行其他线程,其他线程阻塞。
实例
package java_demo.多线程;

public class Thread_join implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("我是vip线程!!我正在执行第"+i);
        }
    }

    public static void main(String[] args) {
        Thread_join thread_join = new Thread_join();
        Thread thread = new Thread(thread_join);
        thread.start();

        for (int i = 0; i < 500; i++) {
            System.out.println("我是主线程,我正在执行!!第"+i);
            if (i == 200)
            {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

10.线程的优先级

  • 设置线程优先级

     对象.setpriority(int n) (0<=n<=10)
    
  • 获取线程优先级

     对象.getpriority(int n) 
    

*线程优先级高并不一定代表先调度,只是说概率提高了。
实例

package java_demo.多线程;

public class Thread_priority {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+"————————>"+Thread.currentThread().getPriority());
        Mypriority mypriority = new Mypriority();
        Thread thread1 = new Thread(mypriority,"a");
        Thread thread2 = new Thread(mypriority,"b");
        Thread thread3 = new Thread(mypriority,"c");
        Thread thread4 = new Thread(mypriority,"d");
        Thread thread5 = new Thread(mypriority,"e");
        thread1.start();
        thread2.setPriority(3);
        thread2.start();
        thread3.setPriority(5);
        thread3.start();
        thread4.setPriority(7);
        thread4.start();
        thread5.setPriority(10);
        thread5.start();

    }

}
class Mypriority implements Runnable
{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"————————>"+Thread.currentThread().getPriority());
    }
}

11.守护线程(Deamon)

  1. 线程分为守护线程和用户线程
  2. 虚拟机必须保证用户线程执行完毕
  3. 虚拟机不必等待保护线程执行完毕
  4. 保护线程有垃圾回收,监控内存等等机制

实例

package java_demo.多线程;
/*
守护线程
 */
public class Thread_deamon {
    public static void main(String[] args) {
        Gad gad = new Gad();
        Me me = new Me();
        Thread thread = new Thread(gad);
        thread.setDaemon(true);//false代表用户线程
        thread.start();
        new Thread(me).start();
    }
}
class Gad implements Runnable
{

    @Override
    public void run() {
        while (true)
        {
            System.out.println("上帝守护着你!!");
        }
    }
}

class Me implements Runnable
{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("开开心心活着第"+i+"年!");
        }
        System.out.println("goodbye world!!!!!!");
    }
}

12.线程同步

  • 并发:同一个对象被多个线程操作时,别叫做并发。
  • 线程同步:线程同步其实就是一种等待机制,当多个线程想要他是去操作一个对象时,它们就会进入到这个对象的等待池中形成一个队列,等上一个线程使用结束,下一个线程再使用。
    什么时候用:处理多线程问题时,当多个线程访问一个对象时,并且有的对象还想修改这个对象,这个时候我们就需要线程同步。
  • 线程同步形成条件:队列+锁

*通俗一点来讲,线程同步就像很多人排队去用一个厕所,前面的人进去以后把锁锁上,结束以后把锁打开,下一个进去把锁锁上…
优点:确保了数据在方法中被访问的正确性,安全性。
缺点:降低效率,一个线程持有锁会导致其他需要此锁的线程挂起。(鱼跟熊掌不可兼得)

13.线程池

背景

  • 经常创建和销毁使用量特别大的资源,比如并发情况下的线程,对性能影响很大。

思路

  • 可以提前创建好多个线程放入线程池中,使用时直接取,使用完放入线程池,这样就避免了重复的创建和销毁,实现了重复利用。

优点

  1. 提高了响应速度,减少了创建线程的时间。
  2. 降低了资源的消耗。
  3. 便于线程管理。

实例:

package java_demo.多线程;

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

public class Thread_pool {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService server = Executors.newFixedThreadPool(10);
        Pool pool = new Pool();
        server.execute(pool);
        server.execute(pool);
        server.execute(pool);
        server.execute(pool);
        server.execute(pool);
        //关闭连接
        server.shutdown();
    }
}
class Pool 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、付费专栏及课程。

余额充值